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 1.0 /*Config->get_edit_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()) {
3259 framepos_t the_start;
3262 bool in_command = false;
3264 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3266 boost::shared_ptr<Region> region;
3270 if ((region = (*i)->top_region_at(the_start)) == 0) {
3274 /* now adjust lengths to that we do the right thing
3275 if the selection extends beyond the region
3278 the_start = max (the_start, (framepos_t) region->position());
3279 if (max_framepos - the_start < region->length()) {
3280 the_end = the_start + region->length() - 1;
3282 the_end = max_framepos;
3284 the_end = min (end, the_end);
3285 cnt = the_end - the_start + 1;
3288 begin_reversible_command (_("trim to selection"));
3291 region->clear_changes ();
3292 region->trim_to (the_start, cnt);
3293 _session->add_command (new StatefulDiffCommand (region));
3297 commit_reversible_command ();
3302 Editor::region_fill_track ()
3304 RegionSelection rs = get_regions_from_selection_and_entered ();
3306 if (!_session || rs.empty()) {
3310 framepos_t const end = _session->current_end_frame ();
3311 RegionSelection foo;
3312 bool in_command = false;
3314 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3316 boost::shared_ptr<Region> region ((*i)->region());
3318 boost::shared_ptr<Playlist> pl = region->playlist();
3320 if (end <= region->last_frame()) {
3324 double times = (double) (end - region->last_frame()) / (double) region->length();
3331 begin_reversible_command (Operations::region_fill);
3334 TimeAxisView& tv = (*i)->get_time_axis_view();
3335 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3336 latest_regionviews.clear ();
3337 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3339 pl->clear_changes ();
3340 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3341 _session->add_command (new StatefulDiffCommand (pl));
3345 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3350 selection->set (foo);
3352 commit_reversible_command ();
3357 Editor::region_fill_selection ()
3359 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3363 if (selection->time.empty()) {
3367 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3372 framepos_t start = selection->time[clicked_selection].start;
3373 framepos_t end = selection->time[clicked_selection].end;
3375 boost::shared_ptr<Playlist> playlist;
3377 if (selection->tracks.empty()) {
3381 framepos_t selection_length = end - start;
3382 float times = (float)selection_length / region->length();
3383 bool in_command = false;
3385 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3386 RegionSelection foo;
3388 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3390 if ((playlist = (*i)->playlist()) == 0) {
3395 begin_reversible_command (Operations::fill_selection);
3398 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3399 latest_regionviews.clear ();
3400 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3402 playlist->clear_changes ();
3403 playlist->add_region (RegionFactory::create (region, true), start, times);
3404 _session->add_command (new StatefulDiffCommand (playlist));
3406 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3411 selection->set (foo);
3413 commit_reversible_command ();
3418 Editor::set_region_sync_position ()
3420 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3424 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3426 bool in_command = false;
3428 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3430 if (!(*r)->region()->covers (where)) {
3434 boost::shared_ptr<Region> region ((*r)->region());
3437 begin_reversible_command (_("set sync point"));
3441 region->clear_changes ();
3442 region->set_sync_position (where);
3443 _session->add_command(new StatefulDiffCommand (region));
3447 commit_reversible_command ();
3451 /** Remove the sync positions of the selection */
3453 Editor::remove_region_sync ()
3455 RegionSelection rs = get_regions_from_selection_and_entered ();
3461 begin_reversible_command (_("remove region sync"));
3463 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3465 (*i)->region()->clear_changes ();
3466 (*i)->region()->clear_sync_position ();
3467 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3470 commit_reversible_command ();
3474 Editor::naturalize_region ()
3476 RegionSelection rs = get_regions_from_selection_and_entered ();
3482 if (rs.size() > 1) {
3483 begin_reversible_command (_("move regions to original position"));
3485 begin_reversible_command (_("move region to original position"));
3488 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3489 (*i)->region()->clear_changes ();
3490 (*i)->region()->move_to_natural_position ();
3491 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3494 commit_reversible_command ();
3498 Editor::align_regions (RegionPoint what)
3500 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3506 begin_reversible_command (_("align selection"));
3508 framepos_t const position = get_preferred_edit_position ();
3510 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3511 align_region_internal ((*i)->region(), what, position);
3514 commit_reversible_command ();
3517 struct RegionSortByTime {
3518 bool operator() (const RegionView* a, const RegionView* b) {
3519 return a->region()->position() < b->region()->position();
3524 Editor::align_regions_relative (RegionPoint point)
3526 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3532 framepos_t const position = get_preferred_edit_position ();
3534 framepos_t distance = 0;
3538 list<RegionView*> sorted;
3539 rs.by_position (sorted);
3541 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3546 if (position > r->position()) {
3547 distance = position - r->position();
3549 distance = r->position() - position;
3555 if (position > r->last_frame()) {
3556 distance = position - r->last_frame();
3557 pos = r->position() + distance;
3559 distance = r->last_frame() - position;
3560 pos = r->position() - distance;
3566 pos = r->adjust_to_sync (position);
3567 if (pos > r->position()) {
3568 distance = pos - r->position();
3570 distance = r->position() - pos;
3576 if (pos == r->position()) {
3580 begin_reversible_command (_("align selection (relative)"));
3582 /* move first one specially */
3584 r->clear_changes ();
3585 r->set_position (pos);
3586 _session->add_command(new StatefulDiffCommand (r));
3588 /* move rest by the same amount */
3592 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3594 boost::shared_ptr<Region> region ((*i)->region());
3596 region->clear_changes ();
3599 region->set_position (region->position() + distance);
3601 region->set_position (region->position() - distance);
3604 _session->add_command(new StatefulDiffCommand (region));
3608 commit_reversible_command ();
3612 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3614 begin_reversible_command (_("align region"));
3615 align_region_internal (region, point, position);
3616 commit_reversible_command ();
3620 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3622 region->clear_changes ();
3626 region->set_position (region->adjust_to_sync (position));
3630 if (position > region->length()) {
3631 region->set_position (position - region->length());
3636 region->set_position (position);
3640 _session->add_command(new StatefulDiffCommand (region));
3644 Editor::trim_region_front ()
3650 Editor::trim_region_back ()
3652 trim_region (false);
3656 Editor::trim_region (bool front)
3658 framepos_t where = get_preferred_edit_position();
3659 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3665 begin_reversible_command (front ? _("trim front") : _("trim back"));
3667 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3668 if (!(*i)->region()->locked()) {
3670 (*i)->region()->clear_changes ();
3673 (*i)->region()->trim_front (where);
3674 maybe_locate_with_edit_preroll ( where );
3676 (*i)->region()->trim_end (where);
3677 maybe_locate_with_edit_preroll ( where );
3680 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3684 commit_reversible_command ();
3687 /** Trim the end of the selected regions to the position of the edit cursor */
3689 Editor::trim_region_to_loop ()
3691 Location* loc = _session->locations()->auto_loop_location();
3695 trim_region_to_location (*loc, _("trim to loop"));
3699 Editor::trim_region_to_punch ()
3701 Location* loc = _session->locations()->auto_punch_location();
3705 trim_region_to_location (*loc, _("trim to punch"));
3709 Editor::trim_region_to_location (const Location& loc, const char* str)
3711 RegionSelection rs = get_regions_from_selection_and_entered ();
3712 bool in_command = false;
3714 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3715 RegionView* rv = (*x);
3717 /* require region to span proposed trim */
3718 switch (rv->region()->coverage (loc.start(), loc.end())) {
3719 case Evoral::OverlapInternal:
3725 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3734 if (tav->track() != 0) {
3735 speed = tav->track()->speed();
3738 start = session_frame_to_track_frame (loc.start(), speed);
3739 end = session_frame_to_track_frame (loc.end(), speed);
3741 rv->region()->clear_changes ();
3742 rv->region()->trim_to (start, (end - start));
3745 begin_reversible_command (str);
3748 _session->add_command(new StatefulDiffCommand (rv->region()));
3752 commit_reversible_command ();
3757 Editor::trim_region_to_previous_region_end ()
3759 return trim_to_region(false);
3763 Editor::trim_region_to_next_region_start ()
3765 return trim_to_region(true);
3769 Editor::trim_to_region(bool forward)
3771 RegionSelection rs = get_regions_from_selection_and_entered ();
3772 bool in_command = false;
3774 boost::shared_ptr<Region> next_region;
3776 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3778 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3784 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3792 if (atav->track() != 0) {
3793 speed = atav->track()->speed();
3797 boost::shared_ptr<Region> region = arv->region();
3798 boost::shared_ptr<Playlist> playlist (region->playlist());
3800 region->clear_changes ();
3804 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3810 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3811 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3815 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3821 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3823 arv->region_changed (ARDOUR::bounds_change);
3827 begin_reversible_command (_("trim to region"));
3830 _session->add_command(new StatefulDiffCommand (region));
3834 commit_reversible_command ();
3839 Editor::unfreeze_route ()
3841 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3845 clicked_routeview->track()->unfreeze ();
3849 Editor::_freeze_thread (void* arg)
3851 return static_cast<Editor*>(arg)->freeze_thread ();
3855 Editor::freeze_thread ()
3857 /* create event pool because we may need to talk to the session */
3858 SessionEvent::create_per_thread_pool ("freeze events", 64);
3859 /* create per-thread buffers for process() tree to use */
3860 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3861 current_interthread_info->done = true;
3866 Editor::freeze_route ()
3872 /* stop transport before we start. this is important */
3874 _session->request_transport_speed (0.0);
3876 /* wait for just a little while, because the above call is asynchronous */
3878 Glib::usleep (250000);
3880 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3884 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3886 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3887 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3889 d.set_title (_("Cannot freeze"));
3894 if (clicked_routeview->track()->has_external_redirects()) {
3895 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"
3896 "Freezing will only process the signal as far as the first send/insert/return."),
3897 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3899 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3900 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3901 d.set_title (_("Freeze Limits"));
3903 int response = d.run ();
3906 case Gtk::RESPONSE_CANCEL:
3913 InterThreadInfo itt;
3914 current_interthread_info = &itt;
3916 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3918 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3920 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3922 while (!itt.done && !itt.cancel) {
3923 gtk_main_iteration ();
3926 current_interthread_info = 0;
3930 Editor::bounce_range_selection (bool replace, bool enable_processing)
3932 if (selection->time.empty()) {
3936 TrackSelection views = selection->tracks;
3938 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3940 if (enable_processing) {
3942 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3944 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3946 _("You can't perform this operation because the processing of the signal "
3947 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3948 "You can do this without processing, which is a different operation.")
3950 d.set_title (_("Cannot bounce"));
3957 framepos_t start = selection->time[clicked_selection].start;
3958 framepos_t end = selection->time[clicked_selection].end;
3959 framepos_t cnt = end - start + 1;
3960 bool in_command = false;
3962 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3964 RouteTimeAxisView* rtv;
3966 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3970 boost::shared_ptr<Playlist> playlist;
3972 if ((playlist = rtv->playlist()) == 0) {
3976 InterThreadInfo itt;
3978 playlist->clear_changes ();
3979 playlist->clear_owned_changes ();
3981 boost::shared_ptr<Region> r;
3983 if (enable_processing) {
3984 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3986 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3994 list<AudioRange> ranges;
3995 ranges.push_back (AudioRange (start, start+cnt, 0));
3996 playlist->cut (ranges); // discard result
3997 playlist->add_region (r, start);
4001 begin_reversible_command (_("bounce range"));
4004 vector<Command*> cmds;
4005 playlist->rdiff (cmds);
4006 _session->add_commands (cmds);
4008 _session->add_command (new StatefulDiffCommand (playlist));
4012 commit_reversible_command ();
4016 /** Delete selected regions, automation points or a time range */
4020 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4021 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4022 bool deleted = false;
4023 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4024 deleted = current_mixer_strip->delete_processors ();
4030 /** Cut selected regions, automation points or a time range */
4037 /** Copy selected regions, automation points or a time range */
4045 /** @return true if a Cut, Copy or Clear is possible */
4047 Editor::can_cut_copy () const
4049 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4056 /** Cut, copy or clear selected regions, automation points or a time range.
4057 * @param op Operation (Delete, Cut, Copy or Clear)
4060 Editor::cut_copy (CutCopyOp op)
4062 /* only cancel selection if cut/copy is successful.*/
4068 opname = _("delete");
4077 opname = _("clear");
4081 /* if we're deleting something, and the mouse is still pressed,
4082 the thing we started a drag for will be gone when we release
4083 the mouse button(s). avoid this. see part 2 at the end of
4087 if (op == Delete || op == Cut || op == Clear) {
4088 if (_drags->active ()) {
4093 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4094 cut_buffer->clear ();
4096 if (entered_marker) {
4098 /* cut/delete op while pointing at a marker */
4101 Location* loc = find_location_from_marker (entered_marker, ignored);
4103 if (_session && loc) {
4104 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4111 switch (mouse_mode) {
4114 begin_reversible_command (opname + ' ' + X_("MIDI"));
4116 commit_reversible_command ();
4122 bool did_edit = false;
4124 if (!selection->regions.empty() || !selection->points.empty()) {
4125 begin_reversible_command (opname + ' ' + _("objects"));
4128 if (!selection->regions.empty()) {
4129 cut_copy_regions (op, selection->regions);
4131 if (op == Cut || op == Delete) {
4132 selection->clear_regions ();
4136 if (!selection->points.empty()) {
4137 cut_copy_points (op);
4139 if (op == Cut || op == Delete) {
4140 selection->clear_points ();
4143 } else if (selection->time.empty()) {
4144 framepos_t start, end;
4145 /* no time selection, see if we can get an edit range
4148 if (get_edit_op_range (start, end)) {
4149 selection->set (start, end);
4151 } else if (!selection->time.empty()) {
4152 begin_reversible_command (opname + ' ' + _("range"));
4155 cut_copy_ranges (op);
4157 if (op == Cut || op == Delete) {
4158 selection->clear_time ();
4163 /* reset repeated paste state */
4166 commit_reversible_command ();
4169 if (op == Delete || op == Cut || op == Clear) {
4174 struct AutomationRecord {
4175 AutomationRecord () : state (0) , line(NULL) {}
4176 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4178 XMLNode* state; ///< state before any operation
4179 const AutomationLine* line; ///< line this came from
4180 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4183 /** Cut, copy or clear selected automation points.
4184 * @param op Operation (Cut, Copy or Clear)
4187 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4189 if (selection->points.empty ()) {
4193 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4194 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4196 /* Keep a record of the AutomationLists that we end up using in this operation */
4197 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4200 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4201 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4202 const AutomationLine& line = (*i)->line();
4203 const boost::shared_ptr<AutomationList> al = line.the_list();
4204 if (lists.find (al) == lists.end ()) {
4205 /* We haven't seen this list yet, so make a record for it. This includes
4206 taking a copy of its current state, in case this is needed for undo later.
4208 lists[al] = AutomationRecord (&al->get_state (), &line);
4212 if (op == Cut || op == Copy) {
4213 /* This operation will involve putting things in the cut buffer, so create an empty
4214 ControlList for each of our source lists to put the cut buffer data in.
4216 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4217 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4220 /* Add all selected points to the relevant copy ControlLists */
4221 framepos_t start = std::numeric_limits<framepos_t>::max();
4222 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4223 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4224 AutomationList::const_iterator j = (*i)->model();
4226 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4228 /* Update earliest MIDI start time in beats */
4229 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4231 /* Update earliest session start time in frames */
4232 start = std::min(start, (*i)->line().session_position(j));
4236 /* Snap start time backwards, so copy/paste is snap aligned. */
4238 if (earliest == Evoral::Beats::max()) {
4239 earliest = Evoral::Beats(); // Weird... don't offset
4241 earliest.round_down_to_beat();
4243 if (start == std::numeric_limits<double>::max()) {
4244 start = 0; // Weird... don't offset
4246 snap_to(start, RoundDownMaybe);
4249 const double line_offset = midi ? earliest.to_double() : start;
4250 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4251 /* Correct this copy list so that it is relative to the earliest
4252 start time, so relative ordering between points is preserved
4253 when copying from several lists and the paste starts at the
4254 earliest copied piece of data. */
4255 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4256 (*j)->when -= line_offset;
4259 /* And add it to the cut buffer */
4260 cut_buffer->add (i->second.copy);
4264 if (op == Delete || op == Cut) {
4265 /* This operation needs to remove things from the main AutomationList, so do that now */
4267 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4268 i->first->freeze ();
4271 /* Remove each selected point from its AutomationList */
4272 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4273 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4274 al->erase ((*i)->model ());
4277 /* Thaw the lists and add undo records for them */
4278 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4279 boost::shared_ptr<AutomationList> al = i->first;
4281 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4286 /** Cut, copy or clear selected automation points.
4287 * @param op Operation (Cut, Copy or Clear)
4290 Editor::cut_copy_midi (CutCopyOp op)
4292 Evoral::Beats earliest = Evoral::Beats::max();
4293 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4294 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4296 if (!mrv->selection().empty()) {
4297 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4299 mrv->cut_copy_clear (op);
4301 /* XXX: not ideal, as there may be more than one track involved in the selection */
4302 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4306 if (!selection->points.empty()) {
4307 cut_copy_points (op, earliest, true);
4308 if (op == Cut || op == Delete) {
4309 selection->clear_points ();
4314 struct lt_playlist {
4315 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4316 return a.playlist < b.playlist;
4320 struct PlaylistMapping {
4322 boost::shared_ptr<Playlist> pl;
4324 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4327 /** Remove `clicked_regionview' */
4329 Editor::remove_clicked_region ()
4331 if (clicked_routeview == 0 || clicked_regionview == 0) {
4335 begin_reversible_command (_("remove region"));
4337 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4339 playlist->clear_changes ();
4340 playlist->clear_owned_changes ();
4341 playlist->remove_region (clicked_regionview->region());
4342 if (Config->get_edit_mode() == Ripple)
4343 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4345 /* We might have removed regions, which alters other regions' layering_index,
4346 so we need to do a recursive diff here.
4348 vector<Command*> cmds;
4349 playlist->rdiff (cmds);
4350 _session->add_commands (cmds);
4352 _session->add_command(new StatefulDiffCommand (playlist));
4353 commit_reversible_command ();
4357 /** Remove the selected regions */
4359 Editor::remove_selected_regions ()
4361 RegionSelection rs = get_regions_from_selection_and_entered ();
4363 if (!_session || rs.empty()) {
4367 list<boost::shared_ptr<Region> > regions_to_remove;
4369 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4370 // we can't just remove the region(s) in this loop because
4371 // this removes them from the RegionSelection, and they thus
4372 // disappear from underneath the iterator, and the ++i above
4373 // SEGVs in a puzzling fashion.
4375 // so, first iterate over the regions to be removed from rs and
4376 // add them to the regions_to_remove list, and then
4377 // iterate over the list to actually remove them.
4379 regions_to_remove.push_back ((*i)->region());
4382 vector<boost::shared_ptr<Playlist> > playlists;
4384 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4386 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4389 // is this check necessary?
4393 /* get_regions_from_selection_and_entered() guarantees that
4394 the playlists involved are unique, so there is no need
4398 playlists.push_back (playlist);
4400 playlist->clear_changes ();
4401 playlist->clear_owned_changes ();
4402 playlist->freeze ();
4403 playlist->remove_region (*rl);
4404 if (Config->get_edit_mode() == Ripple)
4405 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4409 vector<boost::shared_ptr<Playlist> >::iterator pl;
4410 bool in_command = false;
4412 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4415 /* We might have removed regions, which alters other regions' layering_index,
4416 so we need to do a recursive diff here.
4420 begin_reversible_command (_("remove region"));
4423 vector<Command*> cmds;
4424 (*pl)->rdiff (cmds);
4425 _session->add_commands (cmds);
4427 _session->add_command(new StatefulDiffCommand (*pl));
4431 commit_reversible_command ();
4435 /** Cut, copy or clear selected regions.
4436 * @param op Operation (Cut, Copy or Clear)
4439 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4441 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4442 a map when we want ordered access to both elements. i think.
4445 vector<PlaylistMapping> pmap;
4447 framepos_t first_position = max_framepos;
4449 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4450 FreezeList freezelist;
4452 /* get ordering correct before we cut/copy */
4454 rs.sort_by_position_and_track ();
4456 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4458 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4460 if (op == Cut || op == Clear || op == Delete) {
4461 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4464 FreezeList::iterator fl;
4466 // only take state if this is a new playlist.
4467 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4473 if (fl == freezelist.end()) {
4474 pl->clear_changes();
4475 pl->clear_owned_changes ();
4477 freezelist.insert (pl);
4482 TimeAxisView* tv = &(*x)->get_time_axis_view();
4483 vector<PlaylistMapping>::iterator z;
4485 for (z = pmap.begin(); z != pmap.end(); ++z) {
4486 if ((*z).tv == tv) {
4491 if (z == pmap.end()) {
4492 pmap.push_back (PlaylistMapping (tv));
4496 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4498 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4501 /* region not yet associated with a playlist (e.g. unfinished
4508 TimeAxisView& tv = (*x)->get_time_axis_view();
4509 boost::shared_ptr<Playlist> npl;
4510 RegionSelection::iterator tmp;
4517 vector<PlaylistMapping>::iterator z;
4519 for (z = pmap.begin(); z != pmap.end(); ++z) {
4520 if ((*z).tv == &tv) {
4525 assert (z != pmap.end());
4528 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4536 boost::shared_ptr<Region> r = (*x)->region();
4537 boost::shared_ptr<Region> _xx;
4543 pl->remove_region (r);
4544 if (Config->get_edit_mode() == Ripple)
4545 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4549 _xx = RegionFactory::create (r);
4550 npl->add_region (_xx, r->position() - first_position);
4551 pl->remove_region (r);
4552 if (Config->get_edit_mode() == Ripple)
4553 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4557 /* copy region before adding, so we're not putting same object into two different playlists */
4558 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4562 pl->remove_region (r);
4563 if (Config->get_edit_mode() == Ripple)
4564 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4573 list<boost::shared_ptr<Playlist> > foo;
4575 /* the pmap is in the same order as the tracks in which selected regions occured */
4577 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4580 foo.push_back ((*i).pl);
4585 cut_buffer->set (foo);
4589 _last_cut_copy_source_track = 0;
4591 _last_cut_copy_source_track = pmap.front().tv;
4595 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4598 /* We might have removed regions, which alters other regions' layering_index,
4599 so we need to do a recursive diff here.
4601 vector<Command*> cmds;
4602 (*pl)->rdiff (cmds);
4603 _session->add_commands (cmds);
4605 _session->add_command (new StatefulDiffCommand (*pl));
4610 Editor::cut_copy_ranges (CutCopyOp op)
4612 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4614 /* Sort the track selection now, so that it if is used, the playlists
4615 selected by the calls below to cut_copy_clear are in the order that
4616 their tracks appear in the editor. This makes things like paste
4617 of ranges work properly.
4620 sort_track_selection (ts);
4623 if (!entered_track) {
4626 ts.push_back (entered_track);
4629 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4630 (*i)->cut_copy_clear (*selection, op);
4635 Editor::paste (float times, bool from_context)
4637 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4639 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4643 Editor::mouse_paste ()
4648 if (!mouse_frame (where, ignored)) {
4653 paste_internal (where, 1);
4657 Editor::paste_internal (framepos_t position, float times)
4659 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4661 if (cut_buffer->empty(internal_editing())) {
4665 if (position == max_framepos) {
4666 position = get_preferred_edit_position();
4667 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4670 if (position == last_paste_pos) {
4671 /* repeated paste in the same position */
4674 /* paste in new location, reset repeated paste state */
4676 last_paste_pos = position;
4679 /* get everything in the correct order */
4682 if (!selection->tracks.empty()) {
4683 /* If there is a track selection, paste into exactly those tracks and
4684 only those tracks. This allows the user to be explicit and override
4685 the below "do the reasonable thing" logic. */
4686 ts = selection->tracks.filter_to_unique_playlists ();
4687 sort_track_selection (ts);
4689 /* Figure out which track to base the paste at. */
4690 TimeAxisView* base_track = NULL;
4691 if (_edit_point == Editing::EditAtMouse && entered_track) {
4692 /* With the mouse edit point, paste onto the track under the mouse. */
4693 base_track = entered_track;
4694 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4695 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4696 base_track = &entered_regionview->get_time_axis_view();
4697 } else if (_last_cut_copy_source_track) {
4698 /* Paste to the track that the cut/copy came from (see mantis #333). */
4699 base_track = _last_cut_copy_source_track;
4701 /* This is "impossible" since we've copied... well, do nothing. */
4705 /* Walk up to parent if necessary, so base track is a route. */
4706 while (base_track->get_parent()) {
4707 base_track = base_track->get_parent();
4710 /* Add base track and all tracks below it. The paste logic will select
4711 the appropriate object types from the cut buffer in relative order. */
4712 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4713 if ((*i)->order() >= base_track->order()) {
4718 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4719 sort_track_selection (ts);
4721 /* Add automation children of each track in order, for pasting several lines. */
4722 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4723 /* Add any automation children for pasting several lines */
4724 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4729 typedef RouteTimeAxisView::AutomationTracks ATracks;
4730 const ATracks& atracks = rtv->automation_tracks();
4731 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4732 i = ts.insert(i, a->second.get());
4737 /* We now have a list of trackviews starting at base_track, including
4738 automation children, in the order shown in the editor, e.g. R1,
4739 R1.A1, R1.A2, R2, R2.A1, ... */
4742 begin_reversible_command (Operations::paste);
4744 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4745 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4746 /* Only one line copied, and one automation track selected. Do a
4747 "greedy" paste from one automation type to another. */
4749 PasteContext ctx(paste_count, times, ItemCounts(), true);
4750 ts.front()->paste (position, *cut_buffer, ctx);
4754 /* Paste into tracks */
4756 PasteContext ctx(paste_count, times, ItemCounts(), false);
4757 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4758 (*i)->paste (position, *cut_buffer, ctx);
4762 commit_reversible_command ();
4766 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4768 if (regions.empty ()) {
4772 boost::shared_ptr<Playlist> playlist;
4773 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4774 RegionSelection foo;
4776 framepos_t const start_frame = regions.start ();
4777 framepos_t const end_frame = regions.end_frame ();
4778 framecnt_t const gap = end_frame - start_frame + 1;
4780 begin_reversible_command (Operations::duplicate_region);
4782 selection->clear_regions ();
4784 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4786 boost::shared_ptr<Region> r ((*i)->region());
4788 TimeAxisView& tv = (*i)->get_time_axis_view();
4789 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4790 latest_regionviews.clear ();
4791 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4793 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4794 playlist = (*i)->region()->playlist();
4795 playlist->clear_changes ();
4796 playlist->duplicate (r, position, gap, times);
4797 _session->add_command(new StatefulDiffCommand (playlist));
4801 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4805 selection->set (foo);
4808 commit_reversible_command ();
4812 Editor::duplicate_selection (float times)
4814 if (selection->time.empty() || selection->tracks.empty()) {
4818 boost::shared_ptr<Playlist> playlist;
4819 vector<boost::shared_ptr<Region> > new_regions;
4820 vector<boost::shared_ptr<Region> >::iterator ri;
4822 create_region_from_selection (new_regions);
4824 if (new_regions.empty()) {
4828 ri = new_regions.begin();
4830 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4831 bool in_command = false;
4833 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4834 if ((playlist = (*i)->playlist()) == 0) {
4837 playlist->clear_changes ();
4839 if (clicked_selection) {
4840 end = selection->time[clicked_selection].end;
4842 end = selection->time.end_frame();
4844 playlist->duplicate (*ri, end + 1, times);
4847 begin_reversible_command (_("duplicate selection"));
4850 _session->add_command (new StatefulDiffCommand (playlist));
4853 if (ri == new_regions.end()) {
4859 commit_reversible_command ();
4863 /** Reset all selected points to the relevant default value */
4865 Editor::reset_point_selection ()
4867 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4868 ARDOUR::AutomationList::iterator j = (*i)->model ();
4869 (*j)->value = (*i)->line().the_list()->default_value ();
4874 Editor::center_playhead ()
4876 float const page = _visible_canvas_width * samples_per_pixel;
4877 center_screen_internal (playhead_cursor->current_frame (), page);
4881 Editor::center_edit_point ()
4883 float const page = _visible_canvas_width * samples_per_pixel;
4884 center_screen_internal (get_preferred_edit_position(), page);
4887 /** Caller must begin and commit a reversible command */
4889 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4891 playlist->clear_changes ();
4893 _session->add_command (new StatefulDiffCommand (playlist));
4897 Editor::nudge_track (bool use_edit, bool forwards)
4899 boost::shared_ptr<Playlist> playlist;
4900 framepos_t distance;
4901 framepos_t next_distance;
4905 start = get_preferred_edit_position();
4910 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4914 if (selection->tracks.empty()) {
4918 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4919 bool in_command = false;
4921 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4923 if ((playlist = (*i)->playlist()) == 0) {
4927 playlist->clear_changes ();
4928 playlist->clear_owned_changes ();
4930 playlist->nudge_after (start, distance, forwards);
4933 begin_reversible_command (_("nudge track"));
4936 vector<Command*> cmds;
4938 playlist->rdiff (cmds);
4939 _session->add_commands (cmds);
4941 _session->add_command (new StatefulDiffCommand (playlist));
4945 commit_reversible_command ();
4950 Editor::remove_last_capture ()
4952 vector<string> choices;
4959 if (Config->get_verify_remove_last_capture()) {
4960 prompt = _("Do you really want to destroy the last capture?"
4961 "\n(This is destructive and cannot be undone)");
4963 choices.push_back (_("No, do nothing."));
4964 choices.push_back (_("Yes, destroy it."));
4966 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4968 if (prompter.run () == 1) {
4969 _session->remove_last_capture ();
4970 _regions->redisplay ();
4974 _session->remove_last_capture();
4975 _regions->redisplay ();
4980 Editor::normalize_region ()
4986 RegionSelection rs = get_regions_from_selection_and_entered ();
4992 NormalizeDialog dialog (rs.size() > 1);
4994 if (dialog.run () == RESPONSE_CANCEL) {
4998 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5001 /* XXX: should really only count audio regions here */
5002 int const regions = rs.size ();
5004 /* Make a list of the selected audio regions' maximum amplitudes, and also
5005 obtain the maximum amplitude of them all.
5007 list<double> max_amps;
5009 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5010 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5012 dialog.descend (1.0 / regions);
5013 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5016 /* the user cancelled the operation */
5020 max_amps.push_back (a);
5021 max_amp = max (max_amp, a);
5026 list<double>::const_iterator a = max_amps.begin ();
5027 bool in_command = false;
5029 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5030 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5035 arv->region()->clear_changes ();
5037 double const amp = dialog.normalize_individually() ? *a : max_amp;
5039 arv->audio_region()->normalize (amp, dialog.target ());
5042 begin_reversible_command (_("normalize"));
5045 _session->add_command (new StatefulDiffCommand (arv->region()));
5051 commit_reversible_command ();
5057 Editor::reset_region_scale_amplitude ()
5063 RegionSelection rs = get_regions_from_selection_and_entered ();
5069 bool in_command = false;
5071 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5072 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5075 arv->region()->clear_changes ();
5076 arv->audio_region()->set_scale_amplitude (1.0f);
5079 begin_reversible_command ("reset gain");
5082 _session->add_command (new StatefulDiffCommand (arv->region()));
5086 commit_reversible_command ();
5091 Editor::adjust_region_gain (bool up)
5093 RegionSelection rs = get_regions_from_selection_and_entered ();
5095 if (!_session || rs.empty()) {
5099 bool in_command = false;
5101 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5102 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5107 arv->region()->clear_changes ();
5109 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5117 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5120 begin_reversible_command ("adjust region gain");
5123 _session->add_command (new StatefulDiffCommand (arv->region()));
5127 commit_reversible_command ();
5133 Editor::reverse_region ()
5139 Reverse rev (*_session);
5140 apply_filter (rev, _("reverse regions"));
5144 Editor::strip_region_silence ()
5150 RegionSelection rs = get_regions_from_selection_and_entered ();
5156 std::list<RegionView*> audio_only;
5158 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5159 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5161 audio_only.push_back (arv);
5165 assert (!audio_only.empty());
5167 StripSilenceDialog d (_session, audio_only);
5168 int const r = d.run ();
5172 if (r == Gtk::RESPONSE_OK) {
5173 ARDOUR::AudioIntervalMap silences;
5174 d.silences (silences);
5175 StripSilence s (*_session, silences, d.fade_length());
5176 apply_filter (s, _("strip silence"), &d);
5181 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5183 Evoral::Sequence<Evoral::Beats>::Notes selected;
5184 mrv.selection_as_notelist (selected, true);
5186 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5187 v.push_back (selected);
5189 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5190 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5192 return op (mrv.midi_region()->model(), pos_beats, v);
5196 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5202 bool in_command = false;
5204 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5205 RegionSelection::const_iterator tmp = r;
5208 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5211 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5214 begin_reversible_command (op.name ());
5218 _session->add_command (cmd);
5226 commit_reversible_command ();
5231 Editor::fork_region ()
5233 RegionSelection rs = get_regions_from_selection_and_entered ();
5239 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5240 bool in_command = false;
5244 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5245 RegionSelection::iterator tmp = r;
5248 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5252 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5253 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5254 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5257 begin_reversible_command (_("Fork Region(s)"));
5260 playlist->clear_changes ();
5261 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5262 _session->add_command(new StatefulDiffCommand (playlist));
5264 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5272 commit_reversible_command ();
5277 Editor::quantize_region ()
5280 quantize_regions(get_regions_from_selection_and_entered ());
5285 Editor::quantize_regions (const RegionSelection& rs)
5287 if (rs.n_midi_regions() == 0) {
5291 if (!quantize_dialog) {
5292 quantize_dialog = new QuantizeDialog (*this);
5295 quantize_dialog->present ();
5296 const int r = quantize_dialog->run ();
5297 quantize_dialog->hide ();
5299 if (r == Gtk::RESPONSE_OK) {
5300 Quantize quant (quantize_dialog->snap_start(),
5301 quantize_dialog->snap_end(),
5302 quantize_dialog->start_grid_size(),
5303 quantize_dialog->end_grid_size(),
5304 quantize_dialog->strength(),
5305 quantize_dialog->swing(),
5306 quantize_dialog->threshold());
5308 apply_midi_note_edit_op (quant, rs);
5313 Editor::legatize_region (bool shrink_only)
5316 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5321 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5323 if (rs.n_midi_regions() == 0) {
5327 Legatize legatize(shrink_only);
5328 apply_midi_note_edit_op (legatize, rs);
5332 Editor::transform_region ()
5335 transform_regions(get_regions_from_selection_and_entered ());
5340 Editor::transform_regions (const RegionSelection& rs)
5342 if (rs.n_midi_regions() == 0) {
5349 const int r = td.run();
5352 if (r == Gtk::RESPONSE_OK) {
5353 Transform transform(td.get());
5354 apply_midi_note_edit_op(transform, rs);
5359 Editor::transpose_region ()
5362 transpose_regions(get_regions_from_selection_and_entered ());
5367 Editor::transpose_regions (const RegionSelection& rs)
5369 if (rs.n_midi_regions() == 0) {
5374 int const r = d.run ();
5376 if (r == RESPONSE_ACCEPT) {
5377 Transpose transpose(d.semitones ());
5378 apply_midi_note_edit_op (transpose, rs);
5383 Editor::insert_patch_change (bool from_context)
5385 RegionSelection rs = get_regions_from_selection_and_entered ();
5391 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5393 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5394 there may be more than one, but the PatchChangeDialog can only offer
5395 one set of patch menus.
5397 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5399 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5400 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5402 if (d.run() == RESPONSE_CANCEL) {
5406 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5407 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5409 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5410 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5417 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5419 RegionSelection rs = get_regions_from_selection_and_entered ();
5425 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5426 bool in_command = false;
5431 int const N = rs.size ();
5433 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5434 RegionSelection::iterator tmp = r;
5437 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5439 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5442 progress->descend (1.0 / N);
5445 if (arv->audio_region()->apply (filter, progress) == 0) {
5447 playlist->clear_changes ();
5448 playlist->clear_owned_changes ();
5450 if (filter.results.empty ()) {
5452 /* no regions returned; remove the old one */
5453 playlist->remove_region (arv->region ());
5457 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5459 /* first region replaces the old one */
5460 playlist->replace_region (arv->region(), *res, (*res)->position());
5464 while (res != filter.results.end()) {
5465 playlist->add_region (*res, (*res)->position());
5470 /* We might have removed regions, which alters other regions' layering_index,
5471 so we need to do a recursive diff here.
5475 begin_reversible_command (command);
5478 vector<Command*> cmds;
5479 playlist->rdiff (cmds);
5480 _session->add_commands (cmds);
5482 _session->add_command(new StatefulDiffCommand (playlist));
5486 progress->ascend ();
5495 commit_reversible_command ();
5500 Editor::external_edit_region ()
5506 Editor::reset_region_gain_envelopes ()
5508 RegionSelection rs = get_regions_from_selection_and_entered ();
5510 if (!_session || rs.empty()) {
5514 bool in_command = false;
5516 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5517 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5519 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5520 XMLNode& before (alist->get_state());
5522 arv->audio_region()->set_default_envelope ();
5525 begin_reversible_command (_("reset region gain"));
5528 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5533 commit_reversible_command ();
5538 Editor::set_region_gain_visibility (RegionView* rv)
5540 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5542 arv->update_envelope_visibility();
5547 Editor::set_gain_envelope_visibility ()
5553 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5554 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5556 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5562 Editor::toggle_gain_envelope_active ()
5564 if (_ignore_region_action) {
5568 RegionSelection rs = get_regions_from_selection_and_entered ();
5570 if (!_session || rs.empty()) {
5574 bool in_command = false;
5576 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5577 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5579 arv->region()->clear_changes ();
5580 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5583 begin_reversible_command (_("region gain envelope active"));
5586 _session->add_command (new StatefulDiffCommand (arv->region()));
5591 commit_reversible_command ();
5596 Editor::toggle_region_lock ()
5598 if (_ignore_region_action) {
5602 RegionSelection rs = get_regions_from_selection_and_entered ();
5604 if (!_session || rs.empty()) {
5608 begin_reversible_command (_("toggle region lock"));
5610 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5611 (*i)->region()->clear_changes ();
5612 (*i)->region()->set_locked (!(*i)->region()->locked());
5613 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5616 commit_reversible_command ();
5620 Editor::toggle_region_video_lock ()
5622 if (_ignore_region_action) {
5626 RegionSelection rs = get_regions_from_selection_and_entered ();
5628 if (!_session || rs.empty()) {
5632 begin_reversible_command (_("Toggle Video Lock"));
5634 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5635 (*i)->region()->clear_changes ();
5636 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5637 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5640 commit_reversible_command ();
5644 Editor::toggle_region_lock_style ()
5646 if (_ignore_region_action) {
5650 RegionSelection rs = get_regions_from_selection_and_entered ();
5652 if (!_session || rs.empty()) {
5656 begin_reversible_command (_("region lock style"));
5658 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5659 (*i)->region()->clear_changes ();
5660 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5661 (*i)->region()->set_position_lock_style (ns);
5662 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5665 commit_reversible_command ();
5669 Editor::toggle_opaque_region ()
5671 if (_ignore_region_action) {
5675 RegionSelection rs = get_regions_from_selection_and_entered ();
5677 if (!_session || rs.empty()) {
5681 begin_reversible_command (_("change region opacity"));
5683 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5684 (*i)->region()->clear_changes ();
5685 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5686 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5689 commit_reversible_command ();
5693 Editor::toggle_record_enable ()
5695 bool new_state = false;
5697 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5698 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5701 if (!rtav->is_track())
5705 new_state = !rtav->track()->record_enabled();
5709 rtav->track()->set_record_enabled (new_state, this);
5714 Editor::toggle_solo ()
5716 bool new_state = false;
5718 boost::shared_ptr<RouteList> rl (new RouteList);
5720 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5721 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5728 new_state = !rtav->route()->soloed ();
5732 rl->push_back (rtav->route());
5735 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5739 Editor::toggle_mute ()
5741 bool new_state = false;
5743 boost::shared_ptr<RouteList> rl (new RouteList);
5745 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5746 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5753 new_state = !rtav->route()->muted();
5757 rl->push_back (rtav->route());
5760 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5764 Editor::toggle_solo_isolate ()
5770 Editor::fade_range ()
5772 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5774 begin_reversible_command (_("fade range"));
5776 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5777 (*i)->fade_range (selection->time);
5780 commit_reversible_command ();
5785 Editor::set_fade_length (bool in)
5787 RegionSelection rs = get_regions_from_selection_and_entered ();
5793 /* we need a region to measure the offset from the start */
5795 RegionView* rv = rs.front ();
5797 framepos_t pos = get_preferred_edit_position();
5801 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5802 /* edit point is outside the relevant region */
5807 if (pos <= rv->region()->position()) {
5811 len = pos - rv->region()->position();
5812 cmd = _("set fade in length");
5814 if (pos >= rv->region()->last_frame()) {
5818 len = rv->region()->last_frame() - pos;
5819 cmd = _("set fade out length");
5822 bool in_command = false;
5824 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5825 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5831 boost::shared_ptr<AutomationList> alist;
5833 alist = tmp->audio_region()->fade_in();
5835 alist = tmp->audio_region()->fade_out();
5838 XMLNode &before = alist->get_state();
5841 tmp->audio_region()->set_fade_in_length (len);
5842 tmp->audio_region()->set_fade_in_active (true);
5844 tmp->audio_region()->set_fade_out_length (len);
5845 tmp->audio_region()->set_fade_out_active (true);
5849 begin_reversible_command (cmd);
5852 XMLNode &after = alist->get_state();
5853 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5857 commit_reversible_command ();
5862 Editor::set_fade_in_shape (FadeShape shape)
5864 RegionSelection rs = get_regions_from_selection_and_entered ();
5869 bool in_command = false;
5871 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5872 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5878 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5879 XMLNode &before = alist->get_state();
5881 tmp->audio_region()->set_fade_in_shape (shape);
5884 begin_reversible_command (_("set fade in shape"));
5887 XMLNode &after = alist->get_state();
5888 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5892 commit_reversible_command ();
5897 Editor::set_fade_out_shape (FadeShape shape)
5899 RegionSelection rs = get_regions_from_selection_and_entered ();
5904 bool in_command = false;
5906 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5907 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5913 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5914 XMLNode &before = alist->get_state();
5916 tmp->audio_region()->set_fade_out_shape (shape);
5919 begin_reversible_command (_("set fade out shape"));
5922 XMLNode &after = alist->get_state();
5923 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5927 commit_reversible_command ();
5932 Editor::set_fade_in_active (bool yn)
5934 RegionSelection rs = get_regions_from_selection_and_entered ();
5939 bool in_command = false;
5941 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5942 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5949 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5951 ar->clear_changes ();
5952 ar->set_fade_in_active (yn);
5955 begin_reversible_command (_("set fade in active"));
5958 _session->add_command (new StatefulDiffCommand (ar));
5962 commit_reversible_command ();
5967 Editor::set_fade_out_active (bool yn)
5969 RegionSelection rs = get_regions_from_selection_and_entered ();
5974 bool in_command = false;
5976 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5977 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5983 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5985 ar->clear_changes ();
5986 ar->set_fade_out_active (yn);
5989 begin_reversible_command (_("set fade out active"));
5992 _session->add_command(new StatefulDiffCommand (ar));
5996 commit_reversible_command ();
6001 Editor::toggle_region_fades (int dir)
6003 if (_ignore_region_action) {
6007 boost::shared_ptr<AudioRegion> ar;
6010 RegionSelection rs = get_regions_from_selection_and_entered ();
6016 RegionSelection::iterator i;
6017 for (i = rs.begin(); i != rs.end(); ++i) {
6018 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6020 yn = ar->fade_out_active ();
6022 yn = ar->fade_in_active ();
6028 if (i == rs.end()) {
6032 /* XXX should this undo-able? */
6033 bool in_command = false;
6035 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6036 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6039 ar->clear_changes ();
6041 if (dir == 1 || dir == 0) {
6042 ar->set_fade_in_active (!yn);
6045 if (dir == -1 || dir == 0) {
6046 ar->set_fade_out_active (!yn);
6049 begin_reversible_command (_("toggle fade active"));
6052 _session->add_command(new StatefulDiffCommand (ar));
6056 commit_reversible_command ();
6061 /** Update region fade visibility after its configuration has been changed */
6063 Editor::update_region_fade_visibility ()
6065 bool _fade_visibility = _session->config.get_show_region_fades ();
6067 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6068 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6070 if (_fade_visibility) {
6071 v->audio_view()->show_all_fades ();
6073 v->audio_view()->hide_all_fades ();
6080 Editor::set_edit_point ()
6085 if (!mouse_frame (where, ignored)) {
6091 if (selection->markers.empty()) {
6093 mouse_add_new_marker (where);
6098 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6101 loc->move_to (where);
6107 Editor::set_playhead_cursor ()
6109 if (entered_marker) {
6110 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6115 if (!mouse_frame (where, ignored)) {
6122 _session->request_locate (where, _session->transport_rolling());
6126 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6127 cancel_time_selection();
6132 Editor::split_region ()
6134 if (_drags->active ()) {
6138 //if a range is selected, separate it
6139 if ( !selection->time.empty()) {
6140 separate_regions_between (selection->time);
6144 //if no range was selected, try to find some regions to split
6145 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6147 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6149 framepos_t where = get_preferred_edit_position ();
6155 split_regions_at (where, rs);
6159 struct EditorOrderRouteSorter {
6160 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6161 return a->order_key () < b->order_key ();
6166 Editor::select_next_route()
6168 if (selection->tracks.empty()) {
6169 selection->set (track_views.front());
6173 TimeAxisView* current = selection->tracks.front();
6177 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6178 if (*i == current) {
6180 if (i != track_views.end()) {
6183 current = (*(track_views.begin()));
6184 //selection->set (*(track_views.begin()));
6189 rui = dynamic_cast<RouteUI *>(current);
6190 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6192 selection->set(current);
6194 ensure_time_axis_view_is_visible (*current, false);
6198 Editor::select_prev_route()
6200 if (selection->tracks.empty()) {
6201 selection->set (track_views.front());
6205 TimeAxisView* current = selection->tracks.front();
6209 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6210 if (*i == current) {
6212 if (i != track_views.rend()) {
6215 current = *(track_views.rbegin());
6220 rui = dynamic_cast<RouteUI *>(current);
6221 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6223 selection->set (current);
6225 ensure_time_axis_view_is_visible (*current, false);
6229 Editor::set_loop_from_selection (bool play)
6231 if (_session == 0) {
6235 framepos_t start, end;
6236 if (!get_selection_extents ( start, end))
6239 set_loop_range (start, end, _("set loop range from selection"));
6242 _session->request_play_loop (true, true);
6247 Editor::set_loop_from_region (bool play)
6249 framepos_t start, end;
6250 if (!get_selection_extents ( start, end))
6253 set_loop_range (start, end, _("set loop range from region"));
6256 _session->request_locate (start, true);
6257 _session->request_play_loop (true);
6262 Editor::set_punch_from_selection ()
6264 if (_session == 0) {
6268 framepos_t start, end;
6269 if (!get_selection_extents ( start, end))
6272 set_punch_range (start, end, _("set punch range from selection"));
6276 Editor::set_session_extents_from_selection ()
6278 if (_session == 0) {
6282 framepos_t start, end;
6283 if (!get_selection_extents ( start, end))
6287 if ((loc = _session->locations()->session_range_location()) == 0) {
6288 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6290 XMLNode &before = loc->get_state();
6292 _session->set_session_extents ( start, end );
6294 XMLNode &after = loc->get_state();
6296 begin_reversible_command (_("set session start/end from selection"));
6298 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6300 commit_reversible_command ();
6305 Editor::set_punch_start_from_edit_point ()
6309 framepos_t start = 0;
6310 framepos_t end = max_framepos;
6312 //use the existing punch end, if any
6313 Location* tpl = transport_punch_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_punch_range (start, end, _("set punch start from EP"));
6338 Editor::set_punch_end_from_edit_point ()
6342 framepos_t start = 0;
6343 framepos_t end = max_framepos;
6345 //use the existing punch start, if any
6346 Location* tpl = transport_punch_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_punch_range (start, end, _("set punch end from EP"));
6366 Editor::set_loop_start_from_edit_point ()
6370 framepos_t start = 0;
6371 framepos_t end = max_framepos;
6373 //use the existing loop end, if any
6374 Location* tpl = transport_loop_location();
6379 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6380 start = _session->audible_frame();
6382 start = get_preferred_edit_position();
6385 //snap the selection start/end
6388 //if there's not already a sensible selection endpoint, go "forever"
6389 if ( start > end ) {
6393 set_loop_range (start, end, _("set loop start from EP"));
6399 Editor::set_loop_end_from_edit_point ()
6403 framepos_t start = 0;
6404 framepos_t end = max_framepos;
6406 //use the existing loop start, if any
6407 Location* tpl = transport_loop_location();
6409 start = tpl->start();
6412 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6413 end = _session->audible_frame();
6415 end = get_preferred_edit_position();
6418 //snap the selection start/end
6421 set_loop_range (start, end, _("set loop end from EP"));
6426 Editor::set_punch_from_region ()
6428 framepos_t start, end;
6429 if (!get_selection_extents ( start, end))
6432 set_punch_range (start, end, _("set punch range from region"));
6436 Editor::pitch_shift_region ()
6438 RegionSelection rs = get_regions_from_selection_and_entered ();
6440 RegionSelection audio_rs;
6441 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6442 if (dynamic_cast<AudioRegionView*> (*i)) {
6443 audio_rs.push_back (*i);
6447 if (audio_rs.empty()) {
6451 pitch_shift (audio_rs, 1.2);
6455 Editor::set_tempo_from_region ()
6457 RegionSelection rs = get_regions_from_selection_and_entered ();
6459 if (!_session || rs.empty()) {
6463 RegionView* rv = rs.front();
6465 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6469 Editor::use_range_as_bar ()
6471 framepos_t start, end;
6472 if (get_edit_op_range (start, end)) {
6473 define_one_bar (start, end);
6478 Editor::define_one_bar (framepos_t start, framepos_t end)
6480 framepos_t length = end - start;
6482 const Meter& m (_session->tempo_map().meter_at (start));
6484 /* length = 1 bar */
6486 /* now we want frames per beat.
6487 we have frames per bar, and beats per bar, so ...
6490 /* XXXX METER MATH */
6492 double frames_per_beat = length / m.divisions_per_bar();
6494 /* beats per minute = */
6496 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6498 /* now decide whether to:
6500 (a) set global tempo
6501 (b) add a new tempo marker
6505 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6507 bool do_global = false;
6509 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6511 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6512 at the start, or create a new marker
6515 vector<string> options;
6516 options.push_back (_("Cancel"));
6517 options.push_back (_("Add new marker"));
6518 options.push_back (_("Set global tempo"));
6521 _("Define one bar"),
6522 _("Do you want to set the global tempo or add a new tempo marker?"),
6526 c.set_default_response (2);
6542 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6543 if the marker is at the region starter, change it, otherwise add
6548 begin_reversible_command (_("set tempo from region"));
6549 XMLNode& before (_session->tempo_map().get_state());
6552 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6553 } else if (t.frame() == start) {
6554 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6556 Timecode::BBT_Time bbt;
6557 _session->tempo_map().bbt_time (start, bbt);
6558 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6561 XMLNode& after (_session->tempo_map().get_state());
6563 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6564 commit_reversible_command ();
6568 Editor::split_region_at_transients ()
6570 AnalysisFeatureList positions;
6572 RegionSelection rs = get_regions_from_selection_and_entered ();
6574 if (!_session || rs.empty()) {
6578 begin_reversible_command (_("split regions"));
6580 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6582 RegionSelection::iterator tmp;
6587 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6589 if (ar && (ar->get_transients (positions) == 0)) {
6590 split_region_at_points ((*i)->region(), positions, true);
6597 commit_reversible_command ();
6602 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6604 bool use_rhythmic_rodent = false;
6606 boost::shared_ptr<Playlist> pl = r->playlist();
6608 list<boost::shared_ptr<Region> > new_regions;
6614 if (positions.empty()) {
6619 if (positions.size() > 20 && can_ferret) {
6620 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);
6621 MessageDialog msg (msgstr,
6624 Gtk::BUTTONS_OK_CANCEL);
6627 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6628 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6630 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6633 msg.set_title (_("Excessive split?"));
6636 int response = msg.run();
6642 case RESPONSE_APPLY:
6643 use_rhythmic_rodent = true;
6650 if (use_rhythmic_rodent) {
6651 show_rhythm_ferret ();
6655 AnalysisFeatureList::const_iterator x;
6657 pl->clear_changes ();
6658 pl->clear_owned_changes ();
6660 x = positions.begin();
6662 if (x == positions.end()) {
6667 pl->remove_region (r);
6671 while (x != positions.end()) {
6673 /* deal with positons that are out of scope of present region bounds */
6674 if (*x <= 0 || *x > r->length()) {
6679 /* file start = original start + how far we from the initial position ?
6682 framepos_t file_start = r->start() + pos;
6684 /* length = next position - current position
6687 framepos_t len = (*x) - pos;
6689 /* XXX we do we really want to allow even single-sample regions?
6690 shouldn't we have some kind of lower limit on region size?
6699 if (RegionFactory::region_name (new_name, r->name())) {
6703 /* do NOT announce new regions 1 by one, just wait till they are all done */
6707 plist.add (ARDOUR::Properties::start, file_start);
6708 plist.add (ARDOUR::Properties::length, len);
6709 plist.add (ARDOUR::Properties::name, new_name);
6710 plist.add (ARDOUR::Properties::layer, 0);
6712 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6713 /* because we set annouce to false, manually add the new region to the
6716 RegionFactory::map_add (nr);
6718 pl->add_region (nr, r->position() + pos);
6721 new_regions.push_front(nr);
6730 RegionFactory::region_name (new_name, r->name());
6732 /* Add the final region */
6735 plist.add (ARDOUR::Properties::start, r->start() + pos);
6736 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6737 plist.add (ARDOUR::Properties::name, new_name);
6738 plist.add (ARDOUR::Properties::layer, 0);
6740 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6741 /* because we set annouce to false, manually add the new region to the
6744 RegionFactory::map_add (nr);
6745 pl->add_region (nr, r->position() + pos);
6748 new_regions.push_front(nr);
6753 /* We might have removed regions, which alters other regions' layering_index,
6754 so we need to do a recursive diff here.
6756 vector<Command*> cmds;
6758 _session->add_commands (cmds);
6760 _session->add_command (new StatefulDiffCommand (pl));
6764 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6765 set_selected_regionview_from_region_list ((*i), Selection::Add);
6771 Editor::place_transient()
6777 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6783 framepos_t where = get_preferred_edit_position();
6785 begin_reversible_command (_("place transient"));
6787 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6788 framepos_t position = (*r)->region()->position();
6789 (*r)->region()->add_transient(where - position);
6792 commit_reversible_command ();
6796 Editor::remove_transient(ArdourCanvas::Item* item)
6802 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6805 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6806 _arv->remove_transient (*(float*) _line->get_data ("position"));
6810 Editor::snap_regions_to_grid ()
6812 list <boost::shared_ptr<Playlist > > used_playlists;
6814 RegionSelection rs = get_regions_from_selection_and_entered ();
6816 if (!_session || rs.empty()) {
6820 begin_reversible_command (_("snap regions to grid"));
6822 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6824 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6826 if (!pl->frozen()) {
6827 /* we haven't seen this playlist before */
6829 /* remember used playlists so we can thaw them later */
6830 used_playlists.push_back(pl);
6834 framepos_t start_frame = (*r)->region()->first_frame ();
6835 snap_to (start_frame);
6836 (*r)->region()->set_position (start_frame);
6839 while (used_playlists.size() > 0) {
6840 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6842 used_playlists.pop_front();
6845 commit_reversible_command ();
6849 Editor::close_region_gaps ()
6851 list <boost::shared_ptr<Playlist > > used_playlists;
6853 RegionSelection rs = get_regions_from_selection_and_entered ();
6855 if (!_session || rs.empty()) {
6859 Dialog dialog (_("Close Region Gaps"));
6862 table.set_spacings (12);
6863 table.set_border_width (12);
6864 Label* l = manage (left_aligned_label (_("Crossfade length")));
6865 table.attach (*l, 0, 1, 0, 1);
6867 SpinButton spin_crossfade (1, 0);
6868 spin_crossfade.set_range (0, 15);
6869 spin_crossfade.set_increments (1, 1);
6870 spin_crossfade.set_value (5);
6871 table.attach (spin_crossfade, 1, 2, 0, 1);
6873 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6875 l = manage (left_aligned_label (_("Pull-back length")));
6876 table.attach (*l, 0, 1, 1, 2);
6878 SpinButton spin_pullback (1, 0);
6879 spin_pullback.set_range (0, 100);
6880 spin_pullback.set_increments (1, 1);
6881 spin_pullback.set_value(30);
6882 table.attach (spin_pullback, 1, 2, 1, 2);
6884 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6886 dialog.get_vbox()->pack_start (table);
6887 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6888 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6891 if (dialog.run () == RESPONSE_CANCEL) {
6895 framepos_t crossfade_len = spin_crossfade.get_value();
6896 framepos_t pull_back_frames = spin_pullback.get_value();
6898 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6899 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6901 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6903 begin_reversible_command (_("close region gaps"));
6906 boost::shared_ptr<Region> last_region;
6908 rs.sort_by_position_and_track();
6910 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6912 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6914 if (!pl->frozen()) {
6915 /* we haven't seen this playlist before */
6917 /* remember used playlists so we can thaw them later */
6918 used_playlists.push_back(pl);
6922 framepos_t position = (*r)->region()->position();
6924 if (idx == 0 || position < last_region->position()){
6925 last_region = (*r)->region();
6930 (*r)->region()->trim_front( (position - pull_back_frames));
6931 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6933 last_region = (*r)->region();
6938 while (used_playlists.size() > 0) {
6939 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6941 used_playlists.pop_front();
6944 commit_reversible_command ();
6948 Editor::tab_to_transient (bool forward)
6950 AnalysisFeatureList positions;
6952 RegionSelection rs = get_regions_from_selection_and_entered ();
6958 framepos_t pos = _session->audible_frame ();
6960 if (!selection->tracks.empty()) {
6962 /* don't waste time searching for transients in duplicate playlists.
6965 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6967 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6969 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6972 boost::shared_ptr<Track> tr = rtv->track();
6974 boost::shared_ptr<Playlist> pl = tr->playlist ();
6976 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6979 positions.push_back (result);
6992 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6993 (*r)->region()->get_transients (positions);
6997 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7000 AnalysisFeatureList::iterator x;
7002 for (x = positions.begin(); x != positions.end(); ++x) {
7008 if (x != positions.end ()) {
7009 _session->request_locate (*x);
7013 AnalysisFeatureList::reverse_iterator x;
7015 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7021 if (x != positions.rend ()) {
7022 _session->request_locate (*x);
7028 Editor::playhead_forward_to_grid ()
7034 framepos_t pos = playhead_cursor->current_frame ();
7035 if (pos < max_framepos - 1) {
7037 snap_to_internal (pos, RoundUpAlways, false);
7038 _session->request_locate (pos);
7044 Editor::playhead_backward_to_grid ()
7050 framepos_t pos = playhead_cursor->current_frame ();
7053 snap_to_internal (pos, RoundDownAlways, false);
7054 _session->request_locate (pos);
7059 Editor::set_track_height (Height h)
7061 TrackSelection& ts (selection->tracks);
7063 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7064 (*x)->set_height_enum (h);
7069 Editor::toggle_tracks_active ()
7071 TrackSelection& ts (selection->tracks);
7073 bool target = false;
7079 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7080 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7084 target = !rtv->_route->active();
7087 rtv->_route->set_active (target, this);
7093 Editor::remove_tracks ()
7095 /* this will delete GUI objects that may be the subject of an event
7096 handler in which this method is called. Defer actual deletion to the
7097 next idle callback, when all event handling is finished.
7099 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7103 Editor::idle_remove_tracks ()
7106 return false; /* do not call again */
7110 Editor::_remove_tracks ()
7112 TrackSelection& ts (selection->tracks);
7118 vector<string> choices;
7122 const char* trackstr;
7124 vector<boost::shared_ptr<Route> > routes;
7125 bool special_bus = false;
7127 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7128 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7132 if (rtv->is_track()) {
7137 routes.push_back (rtv->_route);
7139 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7144 if (special_bus && !Config->get_allow_special_bus_removal()) {
7145 MessageDialog msg (_("That would be bad news ...."),
7149 msg.set_secondary_text (string_compose (_(
7150 "Removing the master or monitor bus is such a bad idea\n\
7151 that %1 is not going to allow it.\n\
7153 If you really want to do this sort of thing\n\
7154 edit your ardour.rc file to set the\n\
7155 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7162 if (ntracks + nbusses == 0) {
7166 trackstr = P_("track", "tracks", ntracks);
7167 busstr = P_("bus", "busses", nbusses);
7171 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7172 "(You may also lose the playlists associated with the %2)\n\n"
7173 "This action cannot be undone, and the session file will be overwritten!"),
7174 ntracks, trackstr, nbusses, busstr);
7176 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7177 "(You may also lose the playlists associated with the %2)\n\n"
7178 "This action cannot be undone, and the session file will be overwritten!"),
7181 } else if (nbusses) {
7182 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7183 "This action cannot be undone, and the session file will be overwritten"),
7187 choices.push_back (_("No, do nothing."));
7188 if (ntracks + nbusses > 1) {
7189 choices.push_back (_("Yes, remove them."));
7191 choices.push_back (_("Yes, remove it."));
7196 title = string_compose (_("Remove %1"), trackstr);
7198 title = string_compose (_("Remove %1"), busstr);
7201 Choice prompter (title, prompt, choices);
7203 if (prompter.run () != 1) {
7208 Session::StateProtector sp (_session);
7209 DisplaySuspender ds;
7210 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7211 _session->remove_route (*x);
7217 Editor::do_insert_time ()
7219 if (selection->tracks.empty()) {
7223 InsertRemoveTimeDialog d (*this);
7224 int response = d.run ();
7226 if (response != RESPONSE_OK) {
7230 if (d.distance() == 0) {
7234 InsertTimeOption opt = d.intersected_region_action ();
7237 get_preferred_edit_position(),
7243 d.move_glued_markers(),
7244 d.move_locked_markers(),
7250 Editor::insert_time (
7251 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7252 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7256 if (Config->get_edit_mode() == Lock) {
7259 bool in_command = false;
7261 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7263 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7267 /* don't operate on any playlist more than once, which could
7268 * happen if "all playlists" is enabled, but there is more
7269 * than 1 track using playlists "from" a given track.
7272 set<boost::shared_ptr<Playlist> > pl;
7274 if (all_playlists) {
7275 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7276 if (rtav && rtav->track ()) {
7277 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7278 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7283 if ((*x)->playlist ()) {
7284 pl.insert ((*x)->playlist ());
7288 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7290 (*i)->clear_changes ();
7291 (*i)->clear_owned_changes ();
7293 if (opt == SplitIntersected) {
7297 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7300 begin_reversible_command (_("insert time"));
7303 vector<Command*> cmds;
7305 _session->add_commands (cmds);
7307 _session->add_command (new StatefulDiffCommand (*i));
7311 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7314 begin_reversible_command (_("insert time"));
7317 rtav->route ()->shift (pos, frames);
7324 XMLNode& before (_session->locations()->get_state());
7325 Locations::LocationList copy (_session->locations()->list());
7327 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7329 Locations::LocationList::const_iterator tmp;
7331 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7332 bool const was_locked = (*i)->locked ();
7333 if (locked_markers_too) {
7337 if ((*i)->start() >= pos) {
7338 // move end first, in case we're moving by more than the length of the range
7339 if (!(*i)->is_mark()) {
7340 (*i)->set_end ((*i)->end() + frames);
7342 (*i)->set_start ((*i)->start() + frames);
7354 begin_reversible_command (_("insert time"));
7357 XMLNode& after (_session->locations()->get_state());
7358 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7364 begin_reversible_command (_("insert time"));
7367 XMLNode& before (_session->tempo_map().get_state());
7368 _session->tempo_map().insert_time (pos, frames);
7369 XMLNode& after (_session->tempo_map().get_state());
7370 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7374 commit_reversible_command ();
7379 Editor::do_remove_time ()
7381 if (selection->tracks.empty()) {
7385 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7386 InsertRemoveTimeDialog d (*this, true);
7388 int response = d.run ();
7390 if (response != RESPONSE_OK) {
7394 framecnt_t distance = d.distance();
7396 if (distance == 0) {
7406 d.move_glued_markers(),
7407 d.move_locked_markers(),
7413 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7414 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7416 if (Config->get_edit_mode() == Lock) {
7417 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7420 bool in_command = false;
7422 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7424 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7428 XMLNode &before = pl->get_state();
7430 std::list<AudioRange> rl;
7431 AudioRange ar(pos, pos+frames, 0);
7434 pl->shift (pos, -frames, true, ignore_music_glue);
7437 begin_reversible_command (_("cut time"));
7440 XMLNode &after = pl->get_state();
7442 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7446 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7449 begin_reversible_command (_("cut time"));
7452 rtav->route ()->shift (pos, -frames);
7456 std::list<Location*> loc_kill_list;
7461 XMLNode& before (_session->locations()->get_state());
7462 Locations::LocationList copy (_session->locations()->list());
7464 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7465 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7467 bool const was_locked = (*i)->locked ();
7468 if (locked_markers_too) {
7472 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7473 if ((*i)->end() >= pos
7474 && (*i)->end() < pos+frames
7475 && (*i)->start() >= pos
7476 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7478 loc_kill_list.push_back(*i);
7479 } else { // only start or end is included, try to do the right thing
7480 // move start before moving end, to avoid trying to move the end to before the start
7481 // if we're removing more time than the length of the range
7482 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7483 // start is within cut
7484 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7486 } else if ((*i)->start() >= pos+frames) {
7487 // start (and thus entire range) lies beyond end of cut
7488 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7491 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7492 // end is inside cut
7493 (*i)->set_end (pos); // bring the end to the cut
7495 } else if ((*i)->end() >= pos+frames) {
7496 // end is beyond end of cut
7497 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7502 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7503 loc_kill_list.push_back(*i);
7505 } else if ((*i)->start() >= pos) {
7506 (*i)->set_start ((*i)->start() -frames);
7516 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7517 _session->locations()->remove( *i );
7522 begin_reversible_command (_("cut time"));
7525 XMLNode& after (_session->locations()->get_state());
7526 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7531 XMLNode& before (_session->tempo_map().get_state());
7533 if (_session->tempo_map().remove_time (pos, frames) ) {
7535 begin_reversible_command (_("remove time"));
7538 XMLNode& after (_session->tempo_map().get_state());
7539 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7544 commit_reversible_command ();
7549 Editor::fit_selection ()
7551 if (!selection->tracks.empty()) {
7552 fit_tracks (selection->tracks);
7556 /* no selected tracks - use tracks with selected regions */
7558 if (!selection->regions.empty()) {
7559 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7560 tvl.push_back (&(*r)->get_time_axis_view ());
7566 } else if (internal_editing()) {
7567 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7570 if (entered_track) {
7571 tvl.push_back (entered_track);
7580 Editor::fit_tracks (TrackViewList & tracks)
7582 if (tracks.empty()) {
7586 uint32_t child_heights = 0;
7587 int visible_tracks = 0;
7589 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7591 if (!(*t)->marked_for_display()) {
7595 child_heights += (*t)->effective_height() - (*t)->current_height();
7599 /* compute the per-track height from:
7601 total canvas visible height -
7602 height that will be taken by visible children of selected
7603 tracks - height of the ruler/hscroll area
7605 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7606 double first_y_pos = DBL_MAX;
7608 if (h < TimeAxisView::preset_height (HeightSmall)) {
7609 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7610 /* too small to be displayed */
7614 undo_visual_stack.push_back (current_visual_state (true));
7615 PBD::Unwinder<bool> nsv (no_save_visual, true);
7617 /* build a list of all tracks, including children */
7620 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7622 TimeAxisView::Children c = (*i)->get_child_list ();
7623 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7624 all.push_back (j->get());
7629 // find selection range.
7630 // if someone knows how to user TrackViewList::iterator for this
7632 int selected_top = -1;
7633 int selected_bottom = -1;
7635 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7636 if ((*t)->marked_for_display ()) {
7637 if (tracks.contains(*t)) {
7638 if (selected_top == -1) {
7641 selected_bottom = i;
7647 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7648 if ((*t)->marked_for_display ()) {
7649 if (tracks.contains(*t)) {
7650 (*t)->set_height (h);
7651 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7653 if (i > selected_top && i < selected_bottom) {
7654 hide_track_in_display (*t);
7661 set the controls_layout height now, because waiting for its size
7662 request signal handler will cause the vertical adjustment setting to fail
7665 controls_layout.property_height () = _full_canvas_height;
7666 vertical_adjustment.set_value (first_y_pos);
7668 redo_visual_stack.push_back (current_visual_state (true));
7670 visible_tracks_selector.set_text (_("Sel"));
7674 Editor::save_visual_state (uint32_t n)
7676 while (visual_states.size() <= n) {
7677 visual_states.push_back (0);
7680 if (visual_states[n] != 0) {
7681 delete visual_states[n];
7684 visual_states[n] = current_visual_state (true);
7689 Editor::goto_visual_state (uint32_t n)
7691 if (visual_states.size() <= n) {
7695 if (visual_states[n] == 0) {
7699 use_visual_state (*visual_states[n]);
7703 Editor::start_visual_state_op (uint32_t n)
7705 save_visual_state (n);
7707 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7709 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7710 pup->set_text (buf);
7715 Editor::cancel_visual_state_op (uint32_t n)
7717 goto_visual_state (n);
7721 Editor::toggle_region_mute ()
7723 if (_ignore_region_action) {
7727 RegionSelection rs = get_regions_from_selection_and_entered ();
7733 if (rs.size() > 1) {
7734 begin_reversible_command (_("mute regions"));
7736 begin_reversible_command (_("mute region"));
7739 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7741 (*i)->region()->playlist()->clear_changes ();
7742 (*i)->region()->set_muted (!(*i)->region()->muted ());
7743 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7747 commit_reversible_command ();
7751 Editor::combine_regions ()
7753 /* foreach track with selected regions, take all selected regions
7754 and join them into a new region containing the subregions (as a
7758 typedef set<RouteTimeAxisView*> RTVS;
7761 if (selection->regions.empty()) {
7765 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7766 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7769 tracks.insert (rtv);
7773 begin_reversible_command (_("combine regions"));
7775 vector<RegionView*> new_selection;
7777 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7780 if ((rv = (*i)->combine_regions ()) != 0) {
7781 new_selection.push_back (rv);
7785 selection->clear_regions ();
7786 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7787 selection->add (*i);
7790 commit_reversible_command ();
7794 Editor::uncombine_regions ()
7796 typedef set<RouteTimeAxisView*> RTVS;
7799 if (selection->regions.empty()) {
7803 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7804 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7807 tracks.insert (rtv);
7811 begin_reversible_command (_("uncombine regions"));
7813 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7814 (*i)->uncombine_regions ();
7817 commit_reversible_command ();
7821 Editor::toggle_midi_input_active (bool flip_others)
7824 boost::shared_ptr<RouteList> rl (new RouteList);
7826 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7827 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7833 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7836 rl->push_back (rtav->route());
7837 onoff = !mt->input_active();
7841 _session->set_exclusive_input_active (rl, onoff, flip_others);
7848 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7850 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7851 lock_dialog->get_vbox()->pack_start (*padlock);
7853 ArdourButton* b = manage (new ArdourButton);
7854 b->set_name ("lock button");
7855 b->set_text (_("Click to unlock"));
7856 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7857 lock_dialog->get_vbox()->pack_start (*b);
7859 lock_dialog->get_vbox()->show_all ();
7860 lock_dialog->set_size_request (200, 200);
7863 delete _main_menu_disabler;
7864 _main_menu_disabler = new MainMenuDisabler;
7866 lock_dialog->present ();
7872 lock_dialog->hide ();
7874 delete _main_menu_disabler;
7875 _main_menu_disabler = 0;
7877 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7878 start_lock_event_timing ();
7883 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7885 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7889 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7891 Timers::TimerSuspender t;
7892 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7893 Gtkmm2ext::UI::instance()->flush_pending ();
7897 Editor::bring_all_sources_into_session ()
7904 ArdourDialog w (_("Moving embedded files into session folder"));
7905 w.get_vbox()->pack_start (msg);
7908 /* flush all pending GUI events because we're about to start copying
7912 Timers::TimerSuspender t;
7913 Gtkmm2ext::UI::instance()->flush_pending ();
7917 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));