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"
61 #include "canvas/canvas.h"
64 #include "audio_region_view.h"
65 #include "audio_streamview.h"
66 #include "audio_time_axis.h"
67 #include "automation_region_view.h"
68 #include "automation_time_axis.h"
69 #include "control_point.h"
73 #include "editor_cursors.h"
74 #include "editor_drag.h"
75 #include "editor_regions.h"
76 #include "editor_routes.h"
77 #include "gui_thread.h"
78 #include "insert_remove_time_dialog.h"
79 #include "interthread_progress_window.h"
80 #include "item_counts.h"
82 #include "midi_region_view.h"
83 #include "mixer_strip.h"
84 #include "mouse_cursors.h"
85 #include "normalize_dialog.h"
87 #include "paste_context.h"
88 #include "patch_change_dialog.h"
89 #include "quantize_dialog.h"
90 #include "region_gain_line.h"
91 #include "rgb_macros.h"
92 #include "route_time_axis.h"
93 #include "selection.h"
94 #include "selection_templates.h"
95 #include "streamview.h"
96 #include "strip_silence_dialog.h"
97 #include "time_axis_view.h"
98 #include "transpose_dialog.h"
99 #include "transform_dialog.h"
100 #include "ui_config.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
112 /***********************************************************************
114 ***********************************************************************/
117 Editor::undo (uint32_t n)
119 if (_drags->active ()) {
125 if (_session->undo_depth() == 0) {
126 undo_action->set_sensitive(false);
128 redo_action->set_sensitive(true);
129 begin_selection_op_history ();
134 Editor::redo (uint32_t n)
136 if (_drags->active ()) {
142 if (_session->redo_depth() == 0) {
143 redo_action->set_sensitive(false);
145 undo_action->set_sensitive(true);
146 begin_selection_op_history ();
151 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
155 RegionSelection pre_selected_regions = selection->regions;
156 bool working_on_selection = !pre_selected_regions.empty();
158 list<boost::shared_ptr<Playlist> > used_playlists;
159 list<RouteTimeAxisView*> used_trackviews;
161 if (regions.empty()) {
165 begin_reversible_command (_("split"));
167 // if splitting a single region, and snap-to is using
168 // region boundaries, don't pay attention to them
170 if (regions.size() == 1) {
171 switch (_snap_type) {
172 case SnapToRegionStart:
173 case SnapToRegionSync:
174 case SnapToRegionEnd:
183 EditorFreeze(); /* Emit Signal */
186 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
188 RegionSelection::iterator tmp;
190 /* XXX this test needs to be more complicated, to make sure we really
191 have something to split.
194 if (!(*a)->region()->covers (where)) {
202 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
210 /* we haven't seen this playlist before */
212 /* remember used playlists so we can thaw them later */
213 used_playlists.push_back(pl);
215 TimeAxisView& tv = (*a)->get_time_axis_view();
216 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
218 used_trackviews.push_back (rtv);
225 pl->clear_changes ();
226 pl->split_region ((*a)->region(), where);
227 _session->add_command (new StatefulDiffCommand (pl));
233 latest_regionviews.clear ();
235 vector<sigc::connection> region_added_connections;
237 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
238 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
241 while (used_playlists.size() > 0) {
242 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
244 used_playlists.pop_front();
247 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
252 EditorThaw(); /* Emit Signal */
255 if (working_on_selection) {
256 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
258 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
259 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
260 /* There are three classes of regions that we might want selected after
261 splitting selected regions:
262 - regions selected before the split operation, and unaffected by it
263 - newly-created regions before the split
264 - newly-created regions after the split
267 if (rsas & Existing) {
268 // region selections that existed before the split.
269 selection->add ( pre_selected_regions );
272 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
273 if ((*ri)->region()->position() < where) {
274 // new regions created before the split
275 if (rsas & NewlyCreatedLeft) {
276 selection->add (*ri);
279 // new regions created after the split
280 if (rsas & NewlyCreatedRight) {
281 selection->add (*ri);
285 _ignore_follow_edits = false;
287 _ignore_follow_edits = true;
288 if( working_on_selection ) {
289 selection->add (latest_regionviews); //these are the new regions created after the split
291 _ignore_follow_edits = false;
294 commit_reversible_command ();
297 /** Move one extreme of the current range selection. If more than one range is selected,
298 * the start of the earliest range or the end of the latest range is moved.
300 * @param move_end true to move the end of the current range selection, false to move
302 * @param next true to move the extreme to the next region boundary, false to move to
306 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
308 if (selection->time.start() == selection->time.end_frame()) {
312 framepos_t start = selection->time.start ();
313 framepos_t end = selection->time.end_frame ();
315 /* the position of the thing we may move */
316 framepos_t pos = move_end ? end : start;
317 int dir = next ? 1 : -1;
319 /* so we don't find the current region again */
320 if (dir > 0 || pos > 0) {
324 framepos_t const target = get_region_boundary (pos, dir, true, false);
339 begin_reversible_selection_op (_("alter selection"));
340 selection->set_preserving_all_ranges (start, end);
341 commit_reversible_selection_op ();
345 Editor::nudge_forward_release (GdkEventButton* ev)
347 if (ev->state & Keyboard::PrimaryModifier) {
348 nudge_forward (false, true);
350 nudge_forward (false, false);
356 Editor::nudge_backward_release (GdkEventButton* ev)
358 if (ev->state & Keyboard::PrimaryModifier) {
359 nudge_backward (false, true);
361 nudge_backward (false, false);
368 Editor::nudge_forward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions forward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
393 r->set_position (r->position() + distance);
394 _session->add_command (new StatefulDiffCommand (r));
397 commit_reversible_command ();
400 } else if (!force_playhead && !selection->markers.empty()) {
403 bool in_command = false;
405 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
407 Location* loc = find_location_from_marker ((*i), is_start);
411 XMLNode& before (loc->get_state());
414 distance = get_nudge_distance (loc->start(), next_distance);
416 distance = next_distance;
418 if (max_framepos - distance > loc->start() + loc->length()) {
419 loc->set_start (loc->start() + distance);
421 loc->set_start (max_framepos - loc->length());
424 distance = get_nudge_distance (loc->end(), next_distance);
426 distance = next_distance;
428 if (max_framepos - distance > loc->end()) {
429 loc->set_end (loc->end() + distance);
431 loc->set_end (max_framepos);
435 begin_reversible_command (_("nudge location forward"));
438 XMLNode& after (loc->get_state());
439 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
444 commit_reversible_command ();
447 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
448 _session->request_locate (playhead_cursor->current_frame () + distance);
453 Editor::nudge_backward (bool next, bool force_playhead)
456 framepos_t next_distance;
462 RegionSelection rs = get_regions_from_selection_and_entered ();
464 if (!force_playhead && !rs.empty()) {
466 begin_reversible_command (_("nudge regions backward"));
468 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
469 boost::shared_ptr<Region> r ((*i)->region());
471 distance = get_nudge_distance (r->position(), next_distance);
474 distance = next_distance;
479 if (r->position() > distance) {
480 r->set_position (r->position() - distance);
484 _session->add_command (new StatefulDiffCommand (r));
487 commit_reversible_command ();
489 } else if (!force_playhead && !selection->markers.empty()) {
492 bool in_command = false;
494 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
496 Location* loc = find_location_from_marker ((*i), is_start);
500 XMLNode& before (loc->get_state());
503 distance = get_nudge_distance (loc->start(), next_distance);
505 distance = next_distance;
507 if (distance < loc->start()) {
508 loc->set_start (loc->start() - distance);
513 distance = get_nudge_distance (loc->end(), next_distance);
516 distance = next_distance;
519 if (distance < loc->end() - loc->length()) {
520 loc->set_end (loc->end() - distance);
522 loc->set_end (loc->length());
526 begin_reversible_command (_("nudge location forward"));
529 XMLNode& after (loc->get_state());
530 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
534 commit_reversible_command ();
539 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
541 if (playhead_cursor->current_frame () > distance) {
542 _session->request_locate (playhead_cursor->current_frame () - distance);
544 _session->goto_start();
550 Editor::nudge_forward_capture_offset ()
552 RegionSelection rs = get_regions_from_selection_and_entered ();
554 if (!_session || rs.empty()) {
558 begin_reversible_command (_("nudge forward"));
560 framepos_t const distance = _session->worst_output_latency();
562 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
563 boost::shared_ptr<Region> r ((*i)->region());
566 r->set_position (r->position() + distance);
567 _session->add_command(new StatefulDiffCommand (r));
570 commit_reversible_command ();
574 Editor::nudge_backward_capture_offset ()
576 RegionSelection rs = get_regions_from_selection_and_entered ();
578 if (!_session || rs.empty()) {
582 begin_reversible_command (_("nudge backward"));
584 framepos_t const distance = _session->worst_output_latency();
586 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
587 boost::shared_ptr<Region> r ((*i)->region());
591 if (r->position() > distance) {
592 r->set_position (r->position() - distance);
596 _session->add_command(new StatefulDiffCommand (r));
599 commit_reversible_command ();
602 struct RegionSelectionPositionSorter {
603 bool operator() (RegionView* a, RegionView* b) {
604 return a->region()->position() < b->region()->position();
609 Editor::sequence_regions ()
612 framepos_t r_end_prev;
620 RegionSelection rs = get_regions_from_selection_and_entered ();
621 rs.sort(RegionSelectionPositionSorter());
625 bool in_command = false;
627 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
628 boost::shared_ptr<Region> r ((*i)->region());
636 if(r->position_locked())
643 r->set_position(r_end_prev);
647 begin_reversible_command (_("sequence regions"));
650 _session->add_command (new StatefulDiffCommand (r));
652 r_end=r->position() + r->length();
658 commit_reversible_command ();
667 Editor::move_to_start ()
669 _session->goto_start ();
673 Editor::move_to_end ()
676 _session->request_locate (_session->current_end_frame());
680 Editor::build_region_boundary_cache ()
683 vector<RegionPoint> interesting_points;
684 boost::shared_ptr<Region> r;
685 TrackViewList tracks;
688 region_boundary_cache.clear ();
694 switch (_snap_type) {
695 case SnapToRegionStart:
696 interesting_points.push_back (Start);
698 case SnapToRegionEnd:
699 interesting_points.push_back (End);
701 case SnapToRegionSync:
702 interesting_points.push_back (SyncPoint);
704 case SnapToRegionBoundary:
705 interesting_points.push_back (Start);
706 interesting_points.push_back (End);
709 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
710 abort(); /*NOTREACHED*/
714 TimeAxisView *ontrack = 0;
717 if (!selection->tracks.empty()) {
718 tlist = selection->tracks.filter_to_unique_playlists ();
720 tlist = track_views.filter_to_unique_playlists ();
723 while (pos < _session->current_end_frame() && !at_end) {
726 framepos_t lpos = max_framepos;
728 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
730 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
731 if (*p == interesting_points.back()) {
734 /* move to next point type */
740 rpos = r->first_frame();
744 rpos = r->last_frame();
748 rpos = r->sync_position ();
756 RouteTimeAxisView *rtav;
758 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
759 if (rtav->track() != 0) {
760 speed = rtav->track()->speed();
764 rpos = track_frame_to_session_frame (rpos, speed);
770 /* prevent duplicates, but we don't use set<> because we want to be able
774 vector<framepos_t>::iterator ri;
776 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
782 if (ri == region_boundary_cache.end()) {
783 region_boundary_cache.push_back (rpos);
790 /* finally sort to be sure that the order is correct */
792 sort (region_boundary_cache.begin(), region_boundary_cache.end());
795 boost::shared_ptr<Region>
796 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
798 TrackViewList::iterator i;
799 framepos_t closest = max_framepos;
800 boost::shared_ptr<Region> ret;
804 framepos_t track_frame;
805 RouteTimeAxisView *rtav;
807 for (i = tracks.begin(); i != tracks.end(); ++i) {
810 boost::shared_ptr<Region> r;
813 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
814 if (rtav->track()!=0)
815 track_speed = rtav->track()->speed();
818 track_frame = session_frame_to_track_frame(frame, track_speed);
820 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
826 rpos = r->first_frame ();
830 rpos = r->last_frame ();
834 rpos = r->sync_position ();
838 // rpos is a "track frame", converting it to "_session frame"
839 rpos = track_frame_to_session_frame(rpos, track_speed);
842 distance = rpos - frame;
844 distance = frame - rpos;
847 if (distance < closest) {
859 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
861 framecnt_t distance = max_framepos;
862 framepos_t current_nearest = -1;
864 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
865 framepos_t contender;
868 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
874 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
878 d = ::llabs (pos - contender);
881 current_nearest = contender;
886 return current_nearest;
890 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
895 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
897 if (!selection->tracks.empty()) {
899 target = find_next_region_boundary (pos, dir, selection->tracks);
903 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
904 get_onscreen_tracks (tvl);
905 target = find_next_region_boundary (pos, dir, tvl);
907 target = find_next_region_boundary (pos, dir, track_views);
913 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
914 get_onscreen_tracks (tvl);
915 target = find_next_region_boundary (pos, dir, tvl);
917 target = find_next_region_boundary (pos, dir, track_views);
925 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
927 framepos_t pos = playhead_cursor->current_frame ();
934 // so we don't find the current region again..
935 if (dir > 0 || pos > 0) {
939 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
943 _session->request_locate (target);
947 Editor::cursor_to_next_region_boundary (bool with_selection)
949 cursor_to_region_boundary (with_selection, 1);
953 Editor::cursor_to_previous_region_boundary (bool with_selection)
955 cursor_to_region_boundary (with_selection, -1);
959 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
961 boost::shared_ptr<Region> r;
962 framepos_t pos = cursor->current_frame ();
968 TimeAxisView *ontrack = 0;
970 // so we don't find the current region again..
974 if (!selection->tracks.empty()) {
976 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
978 } else if (clicked_axisview) {
981 t.push_back (clicked_axisview);
983 r = find_next_region (pos, point, dir, t, &ontrack);
987 r = find_next_region (pos, point, dir, track_views, &ontrack);
996 pos = r->first_frame ();
1000 pos = r->last_frame ();
1004 pos = r->sync_position ();
1009 RouteTimeAxisView *rtav;
1011 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1012 if (rtav->track() != 0) {
1013 speed = rtav->track()->speed();
1017 pos = track_frame_to_session_frame(pos, speed);
1019 if (cursor == playhead_cursor) {
1020 _session->request_locate (pos);
1022 cursor->set_position (pos);
1027 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1029 cursor_to_region_point (cursor, point, 1);
1033 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1035 cursor_to_region_point (cursor, point, -1);
1039 Editor::cursor_to_selection_start (EditorCursor *cursor)
1043 switch (mouse_mode) {
1045 if (!selection->regions.empty()) {
1046 pos = selection->regions.start();
1051 if (!selection->time.empty()) {
1052 pos = selection->time.start ();
1060 if (cursor == playhead_cursor) {
1061 _session->request_locate (pos);
1063 cursor->set_position (pos);
1068 Editor::cursor_to_selection_end (EditorCursor *cursor)
1072 switch (mouse_mode) {
1074 if (!selection->regions.empty()) {
1075 pos = selection->regions.end_frame();
1080 if (!selection->time.empty()) {
1081 pos = selection->time.end_frame ();
1089 if (cursor == playhead_cursor) {
1090 _session->request_locate (pos);
1092 cursor->set_position (pos);
1097 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1107 if (selection->markers.empty()) {
1111 if (!mouse_frame (mouse, ignored)) {
1115 add_location_mark (mouse);
1118 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1122 framepos_t pos = loc->start();
1124 // so we don't find the current region again..
1125 if (dir > 0 || pos > 0) {
1129 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1133 loc->move_to (target);
1137 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1139 selected_marker_to_region_boundary (with_selection, 1);
1143 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1145 selected_marker_to_region_boundary (with_selection, -1);
1149 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1151 boost::shared_ptr<Region> r;
1156 if (!_session || selection->markers.empty()) {
1160 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1164 TimeAxisView *ontrack = 0;
1168 // so we don't find the current region again..
1172 if (!selection->tracks.empty()) {
1174 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1178 r = find_next_region (pos, point, dir, track_views, &ontrack);
1187 pos = r->first_frame ();
1191 pos = r->last_frame ();
1195 pos = r->adjust_to_sync (r->first_frame());
1200 RouteTimeAxisView *rtav;
1202 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1203 if (rtav->track() != 0) {
1204 speed = rtav->track()->speed();
1208 pos = track_frame_to_session_frame(pos, speed);
1214 Editor::selected_marker_to_next_region_point (RegionPoint point)
1216 selected_marker_to_region_point (point, 1);
1220 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1222 selected_marker_to_region_point (point, -1);
1226 Editor::selected_marker_to_selection_start ()
1232 if (!_session || selection->markers.empty()) {
1236 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1240 switch (mouse_mode) {
1242 if (!selection->regions.empty()) {
1243 pos = selection->regions.start();
1248 if (!selection->time.empty()) {
1249 pos = selection->time.start ();
1261 Editor::selected_marker_to_selection_end ()
1267 if (!_session || selection->markers.empty()) {
1271 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1275 switch (mouse_mode) {
1277 if (!selection->regions.empty()) {
1278 pos = selection->regions.end_frame();
1283 if (!selection->time.empty()) {
1284 pos = selection->time.end_frame ();
1296 Editor::scroll_playhead (bool forward)
1298 framepos_t pos = playhead_cursor->current_frame ();
1299 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1302 if (pos == max_framepos) {
1306 if (pos < max_framepos - delta) {
1325 _session->request_locate (pos);
1329 Editor::cursor_align (bool playhead_to_edit)
1335 if (playhead_to_edit) {
1337 if (selection->markers.empty()) {
1341 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1344 /* move selected markers to playhead */
1346 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1349 Location* loc = find_location_from_marker (*i, ignored);
1351 if (loc->is_mark()) {
1352 loc->set_start (playhead_cursor->current_frame ());
1354 loc->set (playhead_cursor->current_frame (),
1355 playhead_cursor->current_frame () + loc->length());
1362 Editor::scroll_backward (float pages)
1364 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1365 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1368 if (leftmost_frame < cnt) {
1371 frame = leftmost_frame - cnt;
1374 reset_x_origin (frame);
1378 Editor::scroll_forward (float pages)
1380 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1381 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1384 if (max_framepos - cnt < leftmost_frame) {
1385 frame = max_framepos - cnt;
1387 frame = leftmost_frame + cnt;
1390 reset_x_origin (frame);
1394 Editor::scroll_tracks_down ()
1396 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1397 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1398 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1401 vertical_adjustment.set_value (vert_value);
1405 Editor::scroll_tracks_up ()
1407 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1411 Editor::scroll_tracks_down_line ()
1413 double vert_value = vertical_adjustment.get_value() + 60;
1415 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1416 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1419 vertical_adjustment.set_value (vert_value);
1423 Editor::scroll_tracks_up_line ()
1425 reset_y_origin (vertical_adjustment.get_value() - 60);
1429 Editor::scroll_down_one_track (bool skip_child_views)
1431 TrackViewList::reverse_iterator next = track_views.rend();
1432 const double top_of_trackviews = vertical_adjustment.get_value();
1434 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1435 if ((*t)->hidden()) {
1439 /* If this is the upper-most visible trackview, we want to display
1440 * the one above it (next)
1442 * Note that covers_y_position() is recursive and includes child views
1444 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1447 if (skip_child_views) {
1450 /* automation lane (one level, non-recursive)
1452 * - if no automation lane exists -> move to next tack
1453 * - if the first (here: bottom-most) matches -> move to next tack
1454 * - if no y-axis match is found -> the current track is at the top
1455 * -> move to last (here: top-most) automation lane
1457 TimeAxisView::Children kids = (*t)->get_child_list();
1458 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1460 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1461 if ((*ci)->hidden()) {
1465 std::pair<TimeAxisView*,double> dev;
1466 dev = (*ci)->covers_y_position (top_of_trackviews);
1468 /* some automation lane is currently at the top */
1469 if (ci == kids.rbegin()) {
1470 /* first (bottom-most) autmation lane is at the top.
1471 * -> move to next track
1480 if (nkid != kids.rend()) {
1481 ensure_time_axis_view_is_visible (**nkid, true);
1489 /* move to the track below the first one that covers the */
1491 if (next != track_views.rend()) {
1492 ensure_time_axis_view_is_visible (**next, true);
1500 Editor::scroll_up_one_track (bool skip_child_views)
1502 TrackViewList::iterator prev = track_views.end();
1503 double top_of_trackviews = vertical_adjustment.get_value ();
1505 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1507 if ((*t)->hidden()) {
1511 /* find the trackview at the top of the trackview group
1513 * Note that covers_y_position() is recursive and includes child views
1515 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1518 if (skip_child_views) {
1521 /* automation lane (one level, non-recursive)
1523 * - if no automation lane exists -> move to prev tack
1524 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1525 * (actually last automation lane of previous track, see below)
1526 * - if first (top-most) lane is at the top -> move to this track
1527 * - else move up one lane
1529 TimeAxisView::Children kids = (*t)->get_child_list();
1530 TimeAxisView::Children::iterator pkid = kids.end();
1532 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1533 if ((*ci)->hidden()) {
1537 std::pair<TimeAxisView*,double> dev;
1538 dev = (*ci)->covers_y_position (top_of_trackviews);
1540 /* some automation lane is currently at the top */
1541 if (ci == kids.begin()) {
1542 /* first (top-most) autmation lane is at the top.
1543 * jump directly to this track's top
1545 ensure_time_axis_view_is_visible (**t, true);
1548 else if (pkid != kids.end()) {
1549 /* some other automation lane is at the top.
1550 * move up to prev automation lane.
1552 ensure_time_axis_view_is_visible (**pkid, true);
1555 assert(0); // not reached
1566 if (prev != track_views.end()) {
1567 // move to bottom-most automation-lane of the previous track
1568 TimeAxisView::Children kids = (*prev)->get_child_list();
1569 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1570 if (!skip_child_views) {
1571 // find the last visible lane
1572 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1573 if (!(*ci)->hidden()) {
1579 if (pkid != kids.rend()) {
1580 ensure_time_axis_view_is_visible (**pkid, true);
1582 ensure_time_axis_view_is_visible (**prev, true);
1593 Editor::tav_zoom_step (bool coarser)
1595 DisplaySuspender ds;
1599 if (selection->tracks.empty()) {
1602 ts = &selection->tracks;
1605 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1606 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1607 tv->step_height (coarser);
1612 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1614 DisplaySuspender ds;
1618 if (selection->tracks.empty() || force_all) {
1621 ts = &selection->tracks;
1624 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1625 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1626 uint32_t h = tv->current_height ();
1631 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1636 tv->set_height (h + 5);
1643 Editor::temporal_zoom_step (bool coarser)
1645 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1647 framecnt_t nspp = samples_per_pixel;
1655 temporal_zoom (nspp);
1659 Editor::temporal_zoom (framecnt_t fpp)
1665 framepos_t current_page = current_page_samples();
1666 framepos_t current_leftmost = leftmost_frame;
1667 framepos_t current_rightmost;
1668 framepos_t current_center;
1669 framepos_t new_page_size;
1670 framepos_t half_page_size;
1671 framepos_t leftmost_after_zoom = 0;
1673 bool in_track_canvas;
1677 if (fpp == samples_per_pixel) {
1681 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1682 // segfaults for lack of memory. If somebody decides this is not high enough I
1683 // believe it can be raisen to higher values but some limit must be in place.
1685 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1686 // all of which is used for the editor track displays. The whole day
1687 // would be 4147200000 samples, so 2592000 samples per pixel.
1689 nfpp = min (fpp, (framecnt_t) 2592000);
1690 nfpp = max ((framecnt_t) 1, nfpp);
1692 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1693 half_page_size = new_page_size / 2;
1695 switch (zoom_focus) {
1697 leftmost_after_zoom = current_leftmost;
1700 case ZoomFocusRight:
1701 current_rightmost = leftmost_frame + current_page;
1702 if (current_rightmost < new_page_size) {
1703 leftmost_after_zoom = 0;
1705 leftmost_after_zoom = current_rightmost - new_page_size;
1709 case ZoomFocusCenter:
1710 current_center = current_leftmost + (current_page/2);
1711 if (current_center < half_page_size) {
1712 leftmost_after_zoom = 0;
1714 leftmost_after_zoom = current_center - half_page_size;
1718 case ZoomFocusPlayhead:
1719 /* centre playhead */
1720 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1723 leftmost_after_zoom = 0;
1724 } else if (l > max_framepos) {
1725 leftmost_after_zoom = max_framepos - new_page_size;
1727 leftmost_after_zoom = (framepos_t) l;
1731 case ZoomFocusMouse:
1732 /* try to keep the mouse over the same point in the display */
1734 if (!mouse_frame (where, in_track_canvas)) {
1735 /* use playhead instead */
1736 where = playhead_cursor->current_frame ();
1738 if (where < half_page_size) {
1739 leftmost_after_zoom = 0;
1741 leftmost_after_zoom = where - half_page_size;
1746 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1749 leftmost_after_zoom = 0;
1750 } else if (l > max_framepos) {
1751 leftmost_after_zoom = max_framepos - new_page_size;
1753 leftmost_after_zoom = (framepos_t) l;
1760 /* try to keep the edit point in the same place */
1761 where = get_preferred_edit_position ();
1765 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1768 leftmost_after_zoom = 0;
1769 } else if (l > max_framepos) {
1770 leftmost_after_zoom = max_framepos - new_page_size;
1772 leftmost_after_zoom = (framepos_t) l;
1776 /* edit point not defined */
1783 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1785 reposition_and_zoom (leftmost_after_zoom, nfpp);
1789 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1791 /* this func helps make sure we leave a little space
1792 at each end of the editor so that the zoom doesn't fit the region
1793 precisely to the screen.
1796 GdkScreen* screen = gdk_screen_get_default ();
1797 const gint pixwidth = gdk_screen_get_width (screen);
1798 const gint mmwidth = gdk_screen_get_width_mm (screen);
1799 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1800 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1802 const framepos_t range = end - start;
1803 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1804 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1806 if (start > extra_samples) {
1807 start -= extra_samples;
1812 if (max_framepos - extra_samples > end) {
1813 end += extra_samples;
1820 Editor::temporal_zoom_region (bool both_axes)
1822 framepos_t start = max_framepos;
1824 set<TimeAxisView*> tracks;
1826 if ( !get_selection_extents(start, end) )
1829 calc_extra_zoom_edges (start, end);
1831 /* if we're zooming on both axes we need to save track heights etc.
1834 undo_visual_stack.push_back (current_visual_state (both_axes));
1836 PBD::Unwinder<bool> nsv (no_save_visual, true);
1838 temporal_zoom_by_frame (start, end);
1841 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1843 /* set visible track heights appropriately */
1845 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1846 (*t)->set_height (per_track_height);
1849 /* hide irrelevant tracks */
1851 DisplaySuspender ds;
1853 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1854 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1855 hide_track_in_display (*i);
1859 vertical_adjustment.set_value (0.0);
1862 redo_visual_stack.push_back (current_visual_state (both_axes));
1867 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1869 start = max_framepos;
1873 //ToDo: if notes are selected, set extents to that selection
1875 //ToDo: if control points are selected, set extents to that selection
1877 if ( !selection->regions.empty() ) {
1878 RegionSelection rs = get_regions_from_selection_and_entered ();
1880 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1882 if ((*i)->region()->position() < start) {
1883 start = (*i)->region()->position();
1886 if ((*i)->region()->last_frame() + 1 > end) {
1887 end = (*i)->region()->last_frame() + 1;
1891 } else if (!selection->time.empty()) {
1892 start = selection->time.start();
1893 end = selection->time.end_frame();
1895 ret = false; //no selection found
1898 if ((start == 0 && end == 0) || end < start) {
1907 Editor::temporal_zoom_selection (bool both_axes)
1909 if (!selection) return;
1911 //ToDo: if notes are selected, zoom to that
1913 //ToDo: if control points are selected, zoom to that
1915 //if region(s) are selected, zoom to that
1916 if ( !selection->regions.empty() )
1917 temporal_zoom_region (both_axes);
1919 //if a range is selected, zoom to that
1920 if (!selection->time.empty()) {
1922 framepos_t start, end;
1923 if (get_selection_extents (start, end)) {
1924 calc_extra_zoom_edges(start, end);
1925 temporal_zoom_by_frame (start, end);
1935 Editor::temporal_zoom_session ()
1937 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1940 framecnt_t start = _session->current_start_frame();
1941 framecnt_t end = _session->current_end_frame();
1943 if (_session->actively_recording () ) {
1944 framepos_t cur = playhead_cursor->current_frame ();
1946 /* recording beyond the end marker; zoom out
1947 * by 5 seconds more so that if 'follow
1948 * playhead' is active we don't immediately
1951 end = cur + _session->frame_rate() * 5;
1955 if ((start == 0 && end == 0) || end < start) {
1959 calc_extra_zoom_edges(start, end);
1961 temporal_zoom_by_frame (start, end);
1966 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1968 if (!_session) return;
1970 if ((start == 0 && end == 0) || end < start) {
1974 framepos_t range = end - start;
1976 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1978 framepos_t new_page = range;
1979 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1980 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1982 if (new_leftmost > middle) {
1986 if (new_leftmost < 0) {
1990 reposition_and_zoom (new_leftmost, new_fpp);
1994 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2000 framecnt_t range_before = frame - leftmost_frame;
2004 if (samples_per_pixel <= 1) {
2007 new_spp = samples_per_pixel + (samples_per_pixel/2);
2009 range_before += range_before/2;
2011 if (samples_per_pixel >= 1) {
2012 new_spp = samples_per_pixel - (samples_per_pixel/2);
2014 /* could bail out here since we cannot zoom any finer,
2015 but leave that to the equality test below
2017 new_spp = samples_per_pixel;
2020 range_before -= range_before/2;
2023 if (new_spp == samples_per_pixel) {
2027 /* zoom focus is automatically taken as @param frame when this
2031 framepos_t new_leftmost = frame - (framepos_t)range_before;
2033 if (new_leftmost > frame) {
2037 if (new_leftmost < 0) {
2041 reposition_and_zoom (new_leftmost, new_spp);
2046 Editor::choose_new_marker_name(string &name) {
2048 if (!UIConfiguration::instance().get_name_new_markers()) {
2049 /* don't prompt user for a new name */
2053 ArdourPrompter dialog (true);
2055 dialog.set_prompt (_("New Name:"));
2057 dialog.set_title (_("New Location Marker"));
2059 dialog.set_name ("MarkNameWindow");
2060 dialog.set_size_request (250, -1);
2061 dialog.set_position (Gtk::WIN_POS_MOUSE);
2063 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2064 dialog.set_initial_text (name);
2068 switch (dialog.run ()) {
2069 case RESPONSE_ACCEPT:
2075 dialog.get_result(name);
2082 Editor::add_location_from_selection ()
2086 if (selection->time.empty()) {
2090 if (_session == 0 || clicked_axisview == 0) {
2094 framepos_t start = selection->time[clicked_selection].start;
2095 framepos_t end = selection->time[clicked_selection].end;
2097 _session->locations()->next_available_name(rangename,"selection");
2098 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2100 begin_reversible_command (_("add marker"));
2102 XMLNode &before = _session->locations()->get_state();
2103 _session->locations()->add (location, true);
2104 XMLNode &after = _session->locations()->get_state();
2105 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2107 commit_reversible_command ();
2111 Editor::add_location_mark (framepos_t where)
2115 select_new_marker = true;
2117 _session->locations()->next_available_name(markername,"mark");
2118 if (!choose_new_marker_name(markername)) {
2121 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2122 begin_reversible_command (_("add marker"));
2124 XMLNode &before = _session->locations()->get_state();
2125 _session->locations()->add (location, true);
2126 XMLNode &after = _session->locations()->get_state();
2127 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2129 commit_reversible_command ();
2133 Editor::set_session_start_from_playhead ()
2139 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2140 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2142 XMLNode &before = loc->get_state();
2144 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2146 XMLNode &after = loc->get_state();
2148 begin_reversible_command (_("Set session start"));
2150 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2152 commit_reversible_command ();
2157 Editor::set_session_end_from_playhead ()
2163 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2164 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2166 XMLNode &before = loc->get_state();
2168 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2170 XMLNode &after = loc->get_state();
2172 begin_reversible_command (_("Set session start"));
2174 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2176 commit_reversible_command ();
2181 Editor::add_location_from_playhead_cursor ()
2183 add_location_mark (_session->audible_frame());
2187 Editor::remove_location_at_playhead_cursor ()
2191 XMLNode &before = _session->locations()->get_state();
2192 bool removed = false;
2194 //find location(s) at this time
2195 Locations::LocationList locs;
2196 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2197 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2198 if ((*i)->is_mark()) {
2199 _session->locations()->remove (*i);
2206 begin_reversible_command (_("remove marker"));
2207 XMLNode &after = _session->locations()->get_state();
2208 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2209 commit_reversible_command ();
2214 /** Add a range marker around each selected region */
2216 Editor::add_locations_from_region ()
2218 RegionSelection rs = get_regions_from_selection_and_entered ();
2223 bool commit = false;
2225 XMLNode &before = _session->locations()->get_state();
2227 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2229 boost::shared_ptr<Region> region = (*i)->region ();
2231 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2233 _session->locations()->add (location, true);
2238 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2239 XMLNode &after = _session->locations()->get_state();
2240 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2241 commit_reversible_command ();
2245 /** Add a single range marker around all selected regions */
2247 Editor::add_location_from_region ()
2249 RegionSelection rs = get_regions_from_selection_and_entered ();
2255 XMLNode &before = _session->locations()->get_state();
2259 if (rs.size() > 1) {
2260 _session->locations()->next_available_name(markername, "regions");
2262 RegionView* rv = *(rs.begin());
2263 boost::shared_ptr<Region> region = rv->region();
2264 markername = region->name();
2267 if (!choose_new_marker_name(markername)) {
2271 // single range spanning all selected
2272 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2273 _session->locations()->add (location, true);
2275 begin_reversible_command (_("add marker"));
2276 XMLNode &after = _session->locations()->get_state();
2277 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2278 commit_reversible_command ();
2284 Editor::jump_forward_to_mark ()
2290 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2296 _session->request_locate (pos, _session->transport_rolling());
2300 Editor::jump_backward_to_mark ()
2306 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2312 _session->request_locate (pos, _session->transport_rolling());
2318 framepos_t const pos = _session->audible_frame ();
2321 _session->locations()->next_available_name (markername, "mark");
2323 if (!choose_new_marker_name (markername)) {
2327 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2331 Editor::clear_markers ()
2334 begin_reversible_command (_("clear markers"));
2336 XMLNode &before = _session->locations()->get_state();
2337 _session->locations()->clear_markers ();
2338 XMLNode &after = _session->locations()->get_state();
2339 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2341 commit_reversible_command ();
2346 Editor::clear_ranges ()
2349 begin_reversible_command (_("clear ranges"));
2351 XMLNode &before = _session->locations()->get_state();
2353 _session->locations()->clear_ranges ();
2355 XMLNode &after = _session->locations()->get_state();
2356 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2358 commit_reversible_command ();
2363 Editor::clear_locations ()
2365 begin_reversible_command (_("clear locations"));
2367 XMLNode &before = _session->locations()->get_state();
2368 _session->locations()->clear ();
2369 XMLNode &after = _session->locations()->get_state();
2370 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2372 commit_reversible_command ();
2376 Editor::unhide_markers ()
2378 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2379 Location *l = (*i).first;
2380 if (l->is_hidden() && l->is_mark()) {
2381 l->set_hidden(false, this);
2387 Editor::unhide_ranges ()
2389 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2390 Location *l = (*i).first;
2391 if (l->is_hidden() && l->is_range_marker()) {
2392 l->set_hidden(false, this);
2397 /* INSERT/REPLACE */
2400 Editor::insert_region_list_selection (float times)
2402 RouteTimeAxisView *tv = 0;
2403 boost::shared_ptr<Playlist> playlist;
2405 if (clicked_routeview != 0) {
2406 tv = clicked_routeview;
2407 } else if (!selection->tracks.empty()) {
2408 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2411 } else if (entered_track != 0) {
2412 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2419 if ((playlist = tv->playlist()) == 0) {
2423 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2428 begin_reversible_command (_("insert region"));
2429 playlist->clear_changes ();
2430 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2431 if (Config->get_edit_mode() == Ripple)
2432 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2434 _session->add_command(new StatefulDiffCommand (playlist));
2435 commit_reversible_command ();
2438 /* BUILT-IN EFFECTS */
2441 Editor::reverse_selection ()
2446 /* GAIN ENVELOPE EDITING */
2449 Editor::edit_envelope ()
2456 Editor::transition_to_rolling (bool fwd)
2462 if (_session->config.get_external_sync()) {
2463 switch (Config->get_sync_source()) {
2467 /* transport controlled by the master */
2472 if (_session->is_auditioning()) {
2473 _session->cancel_audition ();
2477 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2481 Editor::play_from_start ()
2483 _session->request_locate (_session->current_start_frame(), true);
2487 Editor::play_from_edit_point ()
2489 _session->request_locate (get_preferred_edit_position(), true);
2493 Editor::play_from_edit_point_and_return ()
2495 framepos_t start_frame;
2496 framepos_t return_frame;
2498 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2500 if (_session->transport_rolling()) {
2501 _session->request_locate (start_frame, false);
2505 /* don't reset the return frame if its already set */
2507 if ((return_frame = _session->requested_return_frame()) < 0) {
2508 return_frame = _session->audible_frame();
2511 if (start_frame >= 0) {
2512 _session->request_roll_at_and_return (start_frame, return_frame);
2517 Editor::play_selection ()
2519 framepos_t start, end;
2520 if (!get_selection_extents ( start, end))
2523 AudioRange ar (start, end, 0);
2524 list<AudioRange> lar;
2527 _session->request_play_range (&lar, true);
2531 Editor::get_preroll ()
2533 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2538 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2540 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits )
2543 location -= get_preroll();
2545 //don't try to locate before the beginning of time
2549 //if follow_playhead is on, keep the playhead on the screen
2550 if ( _follow_playhead )
2551 if ( location < leftmost_frame )
2552 location = leftmost_frame;
2554 _session->request_locate( location );
2558 Editor::play_with_preroll ()
2561 framepos_t preroll = get_preroll();
2563 framepos_t start, end;
2564 if (!get_selection_extents ( start, end))
2567 if (start > preroll)
2568 start = start - preroll;
2570 end = end + preroll; //"post-roll"
2572 AudioRange ar (start, end, 0);
2573 list<AudioRange> lar;
2576 _session->request_play_range (&lar, true);
2581 Editor::play_location (Location& location)
2583 if (location.start() <= location.end()) {
2587 _session->request_bounded_roll (location.start(), location.end());
2591 Editor::loop_location (Location& location)
2593 if (location.start() <= location.end()) {
2599 if ((tll = transport_loop_location()) != 0) {
2600 tll->set (location.start(), location.end());
2602 // enable looping, reposition and start rolling
2603 _session->request_locate (tll->start(), true);
2604 _session->request_play_loop (true);
2609 Editor::do_layer_operation (LayerOperation op)
2611 if (selection->regions.empty ()) {
2615 bool const multiple = selection->regions.size() > 1;
2619 begin_reversible_command (_("raise regions"));
2621 begin_reversible_command (_("raise region"));
2627 begin_reversible_command (_("raise regions to top"));
2629 begin_reversible_command (_("raise region to top"));
2635 begin_reversible_command (_("lower regions"));
2637 begin_reversible_command (_("lower region"));
2643 begin_reversible_command (_("lower regions to bottom"));
2645 begin_reversible_command (_("lower region"));
2650 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2651 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2652 (*i)->clear_owned_changes ();
2655 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2656 boost::shared_ptr<Region> r = (*i)->region ();
2668 r->lower_to_bottom ();
2672 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2673 vector<Command*> cmds;
2675 _session->add_commands (cmds);
2678 commit_reversible_command ();
2682 Editor::raise_region ()
2684 do_layer_operation (Raise);
2688 Editor::raise_region_to_top ()
2690 do_layer_operation (RaiseToTop);
2694 Editor::lower_region ()
2696 do_layer_operation (Lower);
2700 Editor::lower_region_to_bottom ()
2702 do_layer_operation (LowerToBottom);
2705 /** Show the region editor for the selected regions */
2707 Editor::show_region_properties ()
2709 selection->foreach_regionview (&RegionView::show_region_editor);
2712 /** Show the midi list editor for the selected MIDI regions */
2714 Editor::show_midi_list_editor ()
2716 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2720 Editor::rename_region ()
2722 RegionSelection rs = get_regions_from_selection_and_entered ();
2728 ArdourDialog d (*this, _("Rename Region"), true, false);
2730 Label label (_("New name:"));
2733 hbox.set_spacing (6);
2734 hbox.pack_start (label, false, false);
2735 hbox.pack_start (entry, true, true);
2737 d.get_vbox()->set_border_width (12);
2738 d.get_vbox()->pack_start (hbox, false, false);
2740 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2741 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2743 d.set_size_request (300, -1);
2745 entry.set_text (rs.front()->region()->name());
2746 entry.select_region (0, -1);
2748 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2754 int const ret = d.run();
2758 if (ret != RESPONSE_OK) {
2762 std::string str = entry.get_text();
2763 strip_whitespace_edges (str);
2765 rs.front()->region()->set_name (str);
2766 _regions->redisplay ();
2770 /** Start an audition of the first selected region */
2772 Editor::play_edit_range ()
2774 framepos_t start, end;
2776 if (get_edit_op_range (start, end)) {
2777 _session->request_bounded_roll (start, end);
2782 Editor::play_selected_region ()
2784 framepos_t start = max_framepos;
2787 RegionSelection rs = get_regions_from_selection_and_entered ();
2793 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2794 if ((*i)->region()->position() < start) {
2795 start = (*i)->region()->position();
2797 if ((*i)->region()->last_frame() + 1 > end) {
2798 end = (*i)->region()->last_frame() + 1;
2802 _session->request_bounded_roll (start, end);
2806 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2808 _session->audition_region (region);
2812 Editor::region_from_selection ()
2814 if (clicked_axisview == 0) {
2818 if (selection->time.empty()) {
2822 framepos_t start = selection->time[clicked_selection].start;
2823 framepos_t end = selection->time[clicked_selection].end;
2825 TrackViewList tracks = get_tracks_for_range_action ();
2827 framepos_t selection_cnt = end - start + 1;
2829 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2830 boost::shared_ptr<Region> current;
2831 boost::shared_ptr<Playlist> pl;
2832 framepos_t internal_start;
2835 if ((pl = (*i)->playlist()) == 0) {
2839 if ((current = pl->top_region_at (start)) == 0) {
2843 internal_start = start - current->position();
2844 RegionFactory::region_name (new_name, current->name(), true);
2848 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2849 plist.add (ARDOUR::Properties::length, selection_cnt);
2850 plist.add (ARDOUR::Properties::name, new_name);
2851 plist.add (ARDOUR::Properties::layer, 0);
2853 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2858 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2860 if (selection->time.empty() || selection->tracks.empty()) {
2864 framepos_t start, end;
2865 if (clicked_selection) {
2866 start = selection->time[clicked_selection].start;
2867 end = selection->time[clicked_selection].end;
2869 start = selection->time.start();
2870 end = selection->time.end_frame();
2873 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2874 sort_track_selection (ts);
2876 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2877 boost::shared_ptr<Region> current;
2878 boost::shared_ptr<Playlist> playlist;
2879 framepos_t internal_start;
2882 if ((playlist = (*i)->playlist()) == 0) {
2886 if ((current = playlist->top_region_at(start)) == 0) {
2890 internal_start = start - current->position();
2891 RegionFactory::region_name (new_name, current->name(), true);
2895 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2896 plist.add (ARDOUR::Properties::length, end - start + 1);
2897 plist.add (ARDOUR::Properties::name, new_name);
2899 new_regions.push_back (RegionFactory::create (current, plist));
2904 Editor::split_multichannel_region ()
2906 RegionSelection rs = get_regions_from_selection_and_entered ();
2912 vector< boost::shared_ptr<Region> > v;
2914 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2915 (*x)->region()->separate_by_channel (*_session, v);
2920 Editor::new_region_from_selection ()
2922 region_from_selection ();
2923 cancel_selection ();
2927 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2929 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2930 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2931 case Evoral::OverlapNone:
2939 * - selected tracks, or if there are none...
2940 * - tracks containing selected regions, or if there are none...
2945 Editor::get_tracks_for_range_action () const
2949 if (selection->tracks.empty()) {
2951 /* use tracks with selected regions */
2953 RegionSelection rs = selection->regions;
2955 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2956 TimeAxisView* tv = &(*i)->get_time_axis_view();
2958 if (!t.contains (tv)) {
2964 /* no regions and no tracks: use all tracks */
2970 t = selection->tracks;
2973 return t.filter_to_unique_playlists();
2977 Editor::separate_regions_between (const TimeSelection& ts)
2979 bool in_command = false;
2980 boost::shared_ptr<Playlist> playlist;
2981 RegionSelection new_selection;
2983 TrackViewList tmptracks = get_tracks_for_range_action ();
2984 sort_track_selection (tmptracks);
2986 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2988 RouteTimeAxisView* rtv;
2990 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2992 if (rtv->is_track()) {
2994 /* no edits to destructive tracks */
2996 if (rtv->track()->destructive()) {
3000 if ((playlist = rtv->playlist()) != 0) {
3002 playlist->clear_changes ();
3004 /* XXX need to consider musical time selections here at some point */
3006 double speed = rtv->track()->speed();
3009 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3011 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3012 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3014 latest_regionviews.clear ();
3016 playlist->partition ((framepos_t)((*t).start * speed),
3017 (framepos_t)((*t).end * speed), false);
3021 if (!latest_regionviews.empty()) {
3023 rtv->view()->foreach_regionview (sigc::bind (
3024 sigc::ptr_fun (add_if_covered),
3025 &(*t), &new_selection));
3028 begin_reversible_command (_("separate"));
3032 /* pick up changes to existing regions */
3034 vector<Command*> cmds;
3035 playlist->rdiff (cmds);
3036 _session->add_commands (cmds);
3038 /* pick up changes to the playlist itself (adds/removes)
3041 _session->add_command(new StatefulDiffCommand (playlist));
3050 // selection->set (new_selection);
3052 commit_reversible_command ();
3056 struct PlaylistState {
3057 boost::shared_ptr<Playlist> playlist;
3061 /** Take tracks from get_tracks_for_range_action and cut any regions
3062 * on those tracks so that the tracks are empty over the time
3066 Editor::separate_region_from_selection ()
3068 /* preferentially use *all* ranges in the time selection if we're in range mode
3069 to allow discontiguous operation, since get_edit_op_range() currently
3070 returns a single range.
3073 if (!selection->time.empty()) {
3075 separate_regions_between (selection->time);
3082 if (get_edit_op_range (start, end)) {
3084 AudioRange ar (start, end, 1);
3088 separate_regions_between (ts);
3094 Editor::separate_region_from_punch ()
3096 Location* loc = _session->locations()->auto_punch_location();
3098 separate_regions_using_location (*loc);
3103 Editor::separate_region_from_loop ()
3105 Location* loc = _session->locations()->auto_loop_location();
3107 separate_regions_using_location (*loc);
3112 Editor::separate_regions_using_location (Location& loc)
3114 if (loc.is_mark()) {
3118 AudioRange ar (loc.start(), loc.end(), 1);
3123 separate_regions_between (ts);
3126 /** Separate regions under the selected region */
3128 Editor::separate_under_selected_regions ()
3130 vector<PlaylistState> playlists;
3134 rs = get_regions_from_selection_and_entered();
3136 if (!_session || rs.empty()) {
3140 begin_reversible_command (_("separate region under"));
3142 list<boost::shared_ptr<Region> > regions_to_remove;
3144 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3145 // we can't just remove the region(s) in this loop because
3146 // this removes them from the RegionSelection, and they thus
3147 // disappear from underneath the iterator, and the ++i above
3148 // SEGVs in a puzzling fashion.
3150 // so, first iterate over the regions to be removed from rs and
3151 // add them to the regions_to_remove list, and then
3152 // iterate over the list to actually remove them.
3154 regions_to_remove.push_back ((*i)->region());
3157 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3159 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3162 // is this check necessary?
3166 vector<PlaylistState>::iterator i;
3168 //only take state if this is a new playlist.
3169 for (i = playlists.begin(); i != playlists.end(); ++i) {
3170 if ((*i).playlist == playlist) {
3175 if (i == playlists.end()) {
3177 PlaylistState before;
3178 before.playlist = playlist;
3179 before.before = &playlist->get_state();
3181 playlist->freeze ();
3182 playlists.push_back(before);
3185 //Partition on the region bounds
3186 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3188 //Re-add region that was just removed due to the partition operation
3189 playlist->add_region( (*rl), (*rl)->first_frame() );
3192 vector<PlaylistState>::iterator pl;
3194 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3195 (*pl).playlist->thaw ();
3196 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3199 commit_reversible_command ();
3203 Editor::crop_region_to_selection ()
3205 if (!selection->time.empty()) {
3207 crop_region_to (selection->time.start(), selection->time.end_frame());
3214 if (get_edit_op_range (start, end)) {
3215 crop_region_to (start, end);
3222 Editor::crop_region_to (framepos_t start, framepos_t end)
3224 vector<boost::shared_ptr<Playlist> > playlists;
3225 boost::shared_ptr<Playlist> playlist;
3228 if (selection->tracks.empty()) {
3229 ts = track_views.filter_to_unique_playlists();
3231 ts = selection->tracks.filter_to_unique_playlists ();
3234 sort_track_selection (ts);
3236 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3238 RouteTimeAxisView* rtv;
3240 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3242 boost::shared_ptr<Track> t = rtv->track();
3244 if (t != 0 && ! t->destructive()) {
3246 if ((playlist = rtv->playlist()) != 0) {
3247 playlists.push_back (playlist);
3253 if (playlists.empty()) {
3257 framepos_t the_start;
3260 bool in_command = false;
3262 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3264 boost::shared_ptr<Region> region;
3268 if ((region = (*i)->top_region_at(the_start)) == 0) {
3272 /* now adjust lengths to that we do the right thing
3273 if the selection extends beyond the region
3276 the_start = max (the_start, (framepos_t) region->position());
3277 if (max_framepos - the_start < region->length()) {
3278 the_end = the_start + region->length() - 1;
3280 the_end = max_framepos;
3282 the_end = min (end, the_end);
3283 cnt = the_end - the_start + 1;
3286 begin_reversible_command (_("trim to selection"));
3289 region->clear_changes ();
3290 region->trim_to (the_start, cnt);
3291 _session->add_command (new StatefulDiffCommand (region));
3295 commit_reversible_command ();
3300 Editor::region_fill_track ()
3302 RegionSelection rs = get_regions_from_selection_and_entered ();
3304 if (!_session || rs.empty()) {
3308 framepos_t const end = _session->current_end_frame ();
3309 RegionSelection foo;
3310 bool in_command = false;
3312 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3314 boost::shared_ptr<Region> region ((*i)->region());
3316 boost::shared_ptr<Playlist> pl = region->playlist();
3318 if (end <= region->last_frame()) {
3322 double times = (double) (end - region->last_frame()) / (double) region->length();
3329 begin_reversible_command (Operations::region_fill);
3332 TimeAxisView& tv = (*i)->get_time_axis_view();
3333 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3334 latest_regionviews.clear ();
3335 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3337 pl->clear_changes ();
3338 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3339 _session->add_command (new StatefulDiffCommand (pl));
3343 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3348 selection->set (foo);
3350 commit_reversible_command ();
3355 Editor::region_fill_selection ()
3357 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3361 if (selection->time.empty()) {
3365 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3370 framepos_t start = selection->time[clicked_selection].start;
3371 framepos_t end = selection->time[clicked_selection].end;
3373 boost::shared_ptr<Playlist> playlist;
3375 if (selection->tracks.empty()) {
3379 framepos_t selection_length = end - start;
3380 float times = (float)selection_length / region->length();
3381 bool in_command = false;
3383 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3384 RegionSelection foo;
3386 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3388 if ((playlist = (*i)->playlist()) == 0) {
3393 begin_reversible_command (Operations::fill_selection);
3396 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3397 latest_regionviews.clear ();
3398 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3400 playlist->clear_changes ();
3401 playlist->add_region (RegionFactory::create (region, true), start, times);
3402 _session->add_command (new StatefulDiffCommand (playlist));
3404 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3409 selection->set (foo);
3411 commit_reversible_command ();
3416 Editor::set_region_sync_position ()
3418 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3422 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3424 bool in_command = false;
3426 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3428 if (!(*r)->region()->covers (where)) {
3432 boost::shared_ptr<Region> region ((*r)->region());
3435 begin_reversible_command (_("set sync point"));
3439 region->clear_changes ();
3440 region->set_sync_position (where);
3441 _session->add_command(new StatefulDiffCommand (region));
3445 commit_reversible_command ();
3449 /** Remove the sync positions of the selection */
3451 Editor::remove_region_sync ()
3453 RegionSelection rs = get_regions_from_selection_and_entered ();
3459 begin_reversible_command (_("remove region sync"));
3461 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3463 (*i)->region()->clear_changes ();
3464 (*i)->region()->clear_sync_position ();
3465 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3468 commit_reversible_command ();
3472 Editor::naturalize_region ()
3474 RegionSelection rs = get_regions_from_selection_and_entered ();
3480 if (rs.size() > 1) {
3481 begin_reversible_command (_("move regions to original position"));
3483 begin_reversible_command (_("move region to original position"));
3486 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3487 (*i)->region()->clear_changes ();
3488 (*i)->region()->move_to_natural_position ();
3489 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3492 commit_reversible_command ();
3496 Editor::align_regions (RegionPoint what)
3498 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3504 begin_reversible_command (_("align selection"));
3506 framepos_t const position = get_preferred_edit_position ();
3508 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3509 align_region_internal ((*i)->region(), what, position);
3512 commit_reversible_command ();
3515 struct RegionSortByTime {
3516 bool operator() (const RegionView* a, const RegionView* b) {
3517 return a->region()->position() < b->region()->position();
3522 Editor::align_regions_relative (RegionPoint point)
3524 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3530 framepos_t const position = get_preferred_edit_position ();
3532 framepos_t distance = 0;
3536 list<RegionView*> sorted;
3537 rs.by_position (sorted);
3539 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3544 if (position > r->position()) {
3545 distance = position - r->position();
3547 distance = r->position() - position;
3553 if (position > r->last_frame()) {
3554 distance = position - r->last_frame();
3555 pos = r->position() + distance;
3557 distance = r->last_frame() - position;
3558 pos = r->position() - distance;
3564 pos = r->adjust_to_sync (position);
3565 if (pos > r->position()) {
3566 distance = pos - r->position();
3568 distance = r->position() - pos;
3574 if (pos == r->position()) {
3578 begin_reversible_command (_("align selection (relative)"));
3580 /* move first one specially */
3582 r->clear_changes ();
3583 r->set_position (pos);
3584 _session->add_command(new StatefulDiffCommand (r));
3586 /* move rest by the same amount */
3590 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3592 boost::shared_ptr<Region> region ((*i)->region());
3594 region->clear_changes ();
3597 region->set_position (region->position() + distance);
3599 region->set_position (region->position() - distance);
3602 _session->add_command(new StatefulDiffCommand (region));
3606 commit_reversible_command ();
3610 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3612 begin_reversible_command (_("align region"));
3613 align_region_internal (region, point, position);
3614 commit_reversible_command ();
3618 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3620 region->clear_changes ();
3624 region->set_position (region->adjust_to_sync (position));
3628 if (position > region->length()) {
3629 region->set_position (position - region->length());
3634 region->set_position (position);
3638 _session->add_command(new StatefulDiffCommand (region));
3642 Editor::trim_region_front ()
3648 Editor::trim_region_back ()
3650 trim_region (false);
3654 Editor::trim_region (bool front)
3656 framepos_t where = get_preferred_edit_position();
3657 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3663 begin_reversible_command (front ? _("trim front") : _("trim back"));
3665 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3666 if (!(*i)->region()->locked()) {
3668 (*i)->region()->clear_changes ();
3671 (*i)->region()->trim_front (where);
3672 maybe_locate_with_edit_preroll ( where );
3674 (*i)->region()->trim_end (where);
3675 maybe_locate_with_edit_preroll ( where );
3678 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3682 commit_reversible_command ();
3685 /** Trim the end of the selected regions to the position of the edit cursor */
3687 Editor::trim_region_to_loop ()
3689 Location* loc = _session->locations()->auto_loop_location();
3693 trim_region_to_location (*loc, _("trim to loop"));
3697 Editor::trim_region_to_punch ()
3699 Location* loc = _session->locations()->auto_punch_location();
3703 trim_region_to_location (*loc, _("trim to punch"));
3707 Editor::trim_region_to_location (const Location& loc, const char* str)
3709 RegionSelection rs = get_regions_from_selection_and_entered ();
3710 bool in_command = false;
3712 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3713 RegionView* rv = (*x);
3715 /* require region to span proposed trim */
3716 switch (rv->region()->coverage (loc.start(), loc.end())) {
3717 case Evoral::OverlapInternal:
3723 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3732 if (tav->track() != 0) {
3733 speed = tav->track()->speed();
3736 start = session_frame_to_track_frame (loc.start(), speed);
3737 end = session_frame_to_track_frame (loc.end(), speed);
3739 rv->region()->clear_changes ();
3740 rv->region()->trim_to (start, (end - start));
3743 begin_reversible_command (str);
3746 _session->add_command(new StatefulDiffCommand (rv->region()));
3750 commit_reversible_command ();
3755 Editor::trim_region_to_previous_region_end ()
3757 return trim_to_region(false);
3761 Editor::trim_region_to_next_region_start ()
3763 return trim_to_region(true);
3767 Editor::trim_to_region(bool forward)
3769 RegionSelection rs = get_regions_from_selection_and_entered ();
3770 bool in_command = false;
3772 boost::shared_ptr<Region> next_region;
3774 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3776 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3782 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3790 if (atav->track() != 0) {
3791 speed = atav->track()->speed();
3795 boost::shared_ptr<Region> region = arv->region();
3796 boost::shared_ptr<Playlist> playlist (region->playlist());
3798 region->clear_changes ();
3802 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3808 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3809 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3813 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3819 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3821 arv->region_changed (ARDOUR::bounds_change);
3825 begin_reversible_command (_("trim to region"));
3828 _session->add_command(new StatefulDiffCommand (region));
3832 commit_reversible_command ();
3837 Editor::unfreeze_route ()
3839 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3843 clicked_routeview->track()->unfreeze ();
3847 Editor::_freeze_thread (void* arg)
3849 return static_cast<Editor*>(arg)->freeze_thread ();
3853 Editor::freeze_thread ()
3855 /* create event pool because we may need to talk to the session */
3856 SessionEvent::create_per_thread_pool ("freeze events", 64);
3857 /* create per-thread buffers for process() tree to use */
3858 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3859 current_interthread_info->done = true;
3864 Editor::freeze_route ()
3870 /* stop transport before we start. this is important */
3872 _session->request_transport_speed (0.0);
3874 /* wait for just a little while, because the above call is asynchronous */
3876 Glib::usleep (250000);
3878 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3882 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3884 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3885 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3887 d.set_title (_("Cannot freeze"));
3892 if (clicked_routeview->track()->has_external_redirects()) {
3893 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"
3894 "Freezing will only process the signal as far as the first send/insert/return."),
3895 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3897 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3898 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3899 d.set_title (_("Freeze Limits"));
3901 int response = d.run ();
3904 case Gtk::RESPONSE_CANCEL:
3911 InterThreadInfo itt;
3912 current_interthread_info = &itt;
3914 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3916 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3918 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3920 while (!itt.done && !itt.cancel) {
3921 gtk_main_iteration ();
3924 current_interthread_info = 0;
3928 Editor::bounce_range_selection (bool replace, bool enable_processing)
3930 if (selection->time.empty()) {
3934 TrackSelection views = selection->tracks;
3936 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3938 if (enable_processing) {
3940 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3942 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3944 _("You can't perform this operation because the processing of the signal "
3945 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3946 "You can do this without processing, which is a different operation.")
3948 d.set_title (_("Cannot bounce"));
3955 framepos_t start = selection->time[clicked_selection].start;
3956 framepos_t end = selection->time[clicked_selection].end;
3957 framepos_t cnt = end - start + 1;
3958 bool in_command = false;
3960 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3962 RouteTimeAxisView* rtv;
3964 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3968 boost::shared_ptr<Playlist> playlist;
3970 if ((playlist = rtv->playlist()) == 0) {
3974 InterThreadInfo itt;
3976 playlist->clear_changes ();
3977 playlist->clear_owned_changes ();
3979 boost::shared_ptr<Region> r;
3981 if (enable_processing) {
3982 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3984 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3992 list<AudioRange> ranges;
3993 ranges.push_back (AudioRange (start, start+cnt, 0));
3994 playlist->cut (ranges); // discard result
3995 playlist->add_region (r, start);
3999 begin_reversible_command (_("bounce range"));
4002 vector<Command*> cmds;
4003 playlist->rdiff (cmds);
4004 _session->add_commands (cmds);
4006 _session->add_command (new StatefulDiffCommand (playlist));
4010 commit_reversible_command ();
4014 /** Delete selected regions, automation points or a time range */
4018 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4019 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4020 bool deleted = false;
4021 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4022 deleted = current_mixer_strip->delete_processors ();
4028 /** Cut selected regions, automation points or a time range */
4035 /** Copy selected regions, automation points or a time range */
4043 /** @return true if a Cut, Copy or Clear is possible */
4045 Editor::can_cut_copy () const
4047 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4054 /** Cut, copy or clear selected regions, automation points or a time range.
4055 * @param op Operation (Delete, Cut, Copy or Clear)
4058 Editor::cut_copy (CutCopyOp op)
4060 /* only cancel selection if cut/copy is successful.*/
4066 opname = _("delete");
4075 opname = _("clear");
4079 /* if we're deleting something, and the mouse is still pressed,
4080 the thing we started a drag for will be gone when we release
4081 the mouse button(s). avoid this. see part 2 at the end of
4085 if (op == Delete || op == Cut || op == Clear) {
4086 if (_drags->active ()) {
4091 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4092 cut_buffer->clear ();
4094 if (entered_marker) {
4096 /* cut/delete op while pointing at a marker */
4099 Location* loc = find_location_from_marker (entered_marker, ignored);
4101 if (_session && loc) {
4102 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4109 switch (mouse_mode) {
4112 begin_reversible_command (opname + ' ' + X_("MIDI"));
4114 commit_reversible_command ();
4120 bool did_edit = false;
4122 if (!selection->regions.empty() || !selection->points.empty()) {
4123 begin_reversible_command (opname + ' ' + _("objects"));
4126 if (!selection->regions.empty()) {
4127 cut_copy_regions (op, selection->regions);
4129 if (op == Cut || op == Delete) {
4130 selection->clear_regions ();
4134 if (!selection->points.empty()) {
4135 cut_copy_points (op);
4137 if (op == Cut || op == Delete) {
4138 selection->clear_points ();
4141 } else if (selection->time.empty()) {
4142 framepos_t start, end;
4143 /* no time selection, see if we can get an edit range
4146 if (get_edit_op_range (start, end)) {
4147 selection->set (start, end);
4149 } else if (!selection->time.empty()) {
4150 begin_reversible_command (opname + ' ' + _("range"));
4153 cut_copy_ranges (op);
4155 if (op == Cut || op == Delete) {
4156 selection->clear_time ();
4161 /* reset repeated paste state */
4164 commit_reversible_command ();
4167 if (op == Delete || op == Cut || op == Clear) {
4172 struct AutomationRecord {
4173 AutomationRecord () : state (0) , line(NULL) {}
4174 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4176 XMLNode* state; ///< state before any operation
4177 const AutomationLine* line; ///< line this came from
4178 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4181 /** Cut, copy or clear selected automation points.
4182 * @param op Operation (Cut, Copy or Clear)
4185 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4187 if (selection->points.empty ()) {
4191 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4192 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4194 /* Keep a record of the AutomationLists that we end up using in this operation */
4195 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4198 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4199 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4200 const AutomationLine& line = (*i)->line();
4201 const boost::shared_ptr<AutomationList> al = line.the_list();
4202 if (lists.find (al) == lists.end ()) {
4203 /* We haven't seen this list yet, so make a record for it. This includes
4204 taking a copy of its current state, in case this is needed for undo later.
4206 lists[al] = AutomationRecord (&al->get_state (), &line);
4210 if (op == Cut || op == Copy) {
4211 /* This operation will involve putting things in the cut buffer, so create an empty
4212 ControlList for each of our source lists to put the cut buffer data in.
4214 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4215 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4218 /* Add all selected points to the relevant copy ControlLists */
4219 framepos_t start = std::numeric_limits<framepos_t>::max();
4220 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4221 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4222 AutomationList::const_iterator j = (*i)->model();
4224 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4226 /* Update earliest MIDI start time in beats */
4227 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4229 /* Update earliest session start time in frames */
4230 start = std::min(start, (*i)->line().session_position(j));
4234 /* Snap start time backwards, so copy/paste is snap aligned. */
4236 if (earliest == Evoral::Beats::max()) {
4237 earliest = Evoral::Beats(); // Weird... don't offset
4239 earliest.round_down_to_beat();
4241 if (start == std::numeric_limits<double>::max()) {
4242 start = 0; // Weird... don't offset
4244 snap_to(start, RoundDownMaybe);
4247 const double line_offset = midi ? earliest.to_double() : start;
4248 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4249 /* Correct this copy list so that it is relative to the earliest
4250 start time, so relative ordering between points is preserved
4251 when copying from several lists and the paste starts at the
4252 earliest copied piece of data. */
4253 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4254 (*j)->when -= line_offset;
4257 /* And add it to the cut buffer */
4258 cut_buffer->add (i->second.copy);
4262 if (op == Delete || op == Cut) {
4263 /* This operation needs to remove things from the main AutomationList, so do that now */
4265 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4266 i->first->freeze ();
4269 /* Remove each selected point from its AutomationList */
4270 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4271 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4272 al->erase ((*i)->model ());
4275 /* Thaw the lists and add undo records for them */
4276 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4277 boost::shared_ptr<AutomationList> al = i->first;
4279 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4284 /** Cut, copy or clear selected automation points.
4285 * @param op Operation (Cut, Copy or Clear)
4288 Editor::cut_copy_midi (CutCopyOp op)
4290 Evoral::Beats earliest = Evoral::Beats::max();
4291 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4292 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4294 if (!mrv->selection().empty()) {
4295 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4297 mrv->cut_copy_clear (op);
4299 /* XXX: not ideal, as there may be more than one track involved in the selection */
4300 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4304 if (!selection->points.empty()) {
4305 cut_copy_points (op, earliest, true);
4306 if (op == Cut || op == Delete) {
4307 selection->clear_points ();
4312 struct lt_playlist {
4313 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4314 return a.playlist < b.playlist;
4318 struct PlaylistMapping {
4320 boost::shared_ptr<Playlist> pl;
4322 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4325 /** Remove `clicked_regionview' */
4327 Editor::remove_clicked_region ()
4329 if (clicked_routeview == 0 || clicked_regionview == 0) {
4333 begin_reversible_command (_("remove region"));
4335 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4337 playlist->clear_changes ();
4338 playlist->clear_owned_changes ();
4339 playlist->remove_region (clicked_regionview->region());
4340 if (Config->get_edit_mode() == Ripple)
4341 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4343 /* We might have removed regions, which alters other regions' layering_index,
4344 so we need to do a recursive diff here.
4346 vector<Command*> cmds;
4347 playlist->rdiff (cmds);
4348 _session->add_commands (cmds);
4350 _session->add_command(new StatefulDiffCommand (playlist));
4351 commit_reversible_command ();
4355 /** Remove the selected regions */
4357 Editor::remove_selected_regions ()
4359 RegionSelection rs = get_regions_from_selection_and_entered ();
4361 if (!_session || rs.empty()) {
4365 list<boost::shared_ptr<Region> > regions_to_remove;
4367 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4368 // we can't just remove the region(s) in this loop because
4369 // this removes them from the RegionSelection, and they thus
4370 // disappear from underneath the iterator, and the ++i above
4371 // SEGVs in a puzzling fashion.
4373 // so, first iterate over the regions to be removed from rs and
4374 // add them to the regions_to_remove list, and then
4375 // iterate over the list to actually remove them.
4377 regions_to_remove.push_back ((*i)->region());
4380 vector<boost::shared_ptr<Playlist> > playlists;
4382 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4384 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4387 // is this check necessary?
4391 /* get_regions_from_selection_and_entered() guarantees that
4392 the playlists involved are unique, so there is no need
4396 playlists.push_back (playlist);
4398 playlist->clear_changes ();
4399 playlist->clear_owned_changes ();
4400 playlist->freeze ();
4401 playlist->remove_region (*rl);
4402 if (Config->get_edit_mode() == Ripple)
4403 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4407 vector<boost::shared_ptr<Playlist> >::iterator pl;
4408 bool in_command = false;
4410 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4413 /* We might have removed regions, which alters other regions' layering_index,
4414 so we need to do a recursive diff here.
4418 begin_reversible_command (_("remove region"));
4421 vector<Command*> cmds;
4422 (*pl)->rdiff (cmds);
4423 _session->add_commands (cmds);
4425 _session->add_command(new StatefulDiffCommand (*pl));
4429 commit_reversible_command ();
4433 /** Cut, copy or clear selected regions.
4434 * @param op Operation (Cut, Copy or Clear)
4437 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4439 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4440 a map when we want ordered access to both elements. i think.
4443 vector<PlaylistMapping> pmap;
4445 framepos_t first_position = max_framepos;
4447 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4448 FreezeList freezelist;
4450 /* get ordering correct before we cut/copy */
4452 rs.sort_by_position_and_track ();
4454 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4456 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4458 if (op == Cut || op == Clear || op == Delete) {
4459 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4462 FreezeList::iterator fl;
4464 // only take state if this is a new playlist.
4465 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4471 if (fl == freezelist.end()) {
4472 pl->clear_changes();
4473 pl->clear_owned_changes ();
4475 freezelist.insert (pl);
4480 TimeAxisView* tv = &(*x)->get_time_axis_view();
4481 vector<PlaylistMapping>::iterator z;
4483 for (z = pmap.begin(); z != pmap.end(); ++z) {
4484 if ((*z).tv == tv) {
4489 if (z == pmap.end()) {
4490 pmap.push_back (PlaylistMapping (tv));
4494 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4496 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4499 /* region not yet associated with a playlist (e.g. unfinished
4506 TimeAxisView& tv = (*x)->get_time_axis_view();
4507 boost::shared_ptr<Playlist> npl;
4508 RegionSelection::iterator tmp;
4515 vector<PlaylistMapping>::iterator z;
4517 for (z = pmap.begin(); z != pmap.end(); ++z) {
4518 if ((*z).tv == &tv) {
4523 assert (z != pmap.end());
4526 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4534 boost::shared_ptr<Region> r = (*x)->region();
4535 boost::shared_ptr<Region> _xx;
4541 pl->remove_region (r);
4542 if (Config->get_edit_mode() == Ripple)
4543 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4547 _xx = RegionFactory::create (r);
4548 npl->add_region (_xx, r->position() - first_position);
4549 pl->remove_region (r);
4550 if (Config->get_edit_mode() == Ripple)
4551 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4555 /* copy region before adding, so we're not putting same object into two different playlists */
4556 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4560 pl->remove_region (r);
4561 if (Config->get_edit_mode() == Ripple)
4562 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4571 list<boost::shared_ptr<Playlist> > foo;
4573 /* the pmap is in the same order as the tracks in which selected regions occured */
4575 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4578 foo.push_back ((*i).pl);
4583 cut_buffer->set (foo);
4587 _last_cut_copy_source_track = 0;
4589 _last_cut_copy_source_track = pmap.front().tv;
4593 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4596 /* We might have removed regions, which alters other regions' layering_index,
4597 so we need to do a recursive diff here.
4599 vector<Command*> cmds;
4600 (*pl)->rdiff (cmds);
4601 _session->add_commands (cmds);
4603 _session->add_command (new StatefulDiffCommand (*pl));
4608 Editor::cut_copy_ranges (CutCopyOp op)
4610 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4612 /* Sort the track selection now, so that it if is used, the playlists
4613 selected by the calls below to cut_copy_clear are in the order that
4614 their tracks appear in the editor. This makes things like paste
4615 of ranges work properly.
4618 sort_track_selection (ts);
4621 if (!entered_track) {
4624 ts.push_back (entered_track);
4627 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4628 (*i)->cut_copy_clear (*selection, op);
4633 Editor::paste (float times, bool from_context)
4635 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4637 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4641 Editor::mouse_paste ()
4646 if (!mouse_frame (where, ignored)) {
4651 paste_internal (where, 1);
4655 Editor::paste_internal (framepos_t position, float times)
4657 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4659 if (cut_buffer->empty(internal_editing())) {
4663 if (position == max_framepos) {
4664 position = get_preferred_edit_position();
4665 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4668 if (position == last_paste_pos) {
4669 /* repeated paste in the same position */
4672 /* paste in new location, reset repeated paste state */
4674 last_paste_pos = position;
4677 /* get everything in the correct order */
4680 if (!selection->tracks.empty()) {
4681 /* If there is a track selection, paste into exactly those tracks and
4682 only those tracks. This allows the user to be explicit and override
4683 the below "do the reasonable thing" logic. */
4684 ts = selection->tracks.filter_to_unique_playlists ();
4685 sort_track_selection (ts);
4687 /* Figure out which track to base the paste at. */
4688 TimeAxisView* base_track = NULL;
4689 if (_edit_point == Editing::EditAtMouse && entered_track) {
4690 /* With the mouse edit point, paste onto the track under the mouse. */
4691 base_track = entered_track;
4692 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4693 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4694 base_track = &entered_regionview->get_time_axis_view();
4695 } else if (_last_cut_copy_source_track) {
4696 /* Paste to the track that the cut/copy came from (see mantis #333). */
4697 base_track = _last_cut_copy_source_track;
4699 /* This is "impossible" since we've copied... well, do nothing. */
4703 /* Walk up to parent if necessary, so base track is a route. */
4704 while (base_track->get_parent()) {
4705 base_track = base_track->get_parent();
4708 /* Add base track and all tracks below it. The paste logic will select
4709 the appropriate object types from the cut buffer in relative order. */
4710 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4711 if ((*i)->order() >= base_track->order()) {
4716 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4717 sort_track_selection (ts);
4719 /* Add automation children of each track in order, for pasting several lines. */
4720 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4721 /* Add any automation children for pasting several lines */
4722 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4727 typedef RouteTimeAxisView::AutomationTracks ATracks;
4728 const ATracks& atracks = rtv->automation_tracks();
4729 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4730 i = ts.insert(i, a->second.get());
4735 /* We now have a list of trackviews starting at base_track, including
4736 automation children, in the order shown in the editor, e.g. R1,
4737 R1.A1, R1.A2, R2, R2.A1, ... */
4740 begin_reversible_command (Operations::paste);
4742 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4743 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4744 /* Only one line copied, and one automation track selected. Do a
4745 "greedy" paste from one automation type to another. */
4747 PasteContext ctx(paste_count, times, ItemCounts(), true);
4748 ts.front()->paste (position, *cut_buffer, ctx);
4752 /* Paste into tracks */
4754 PasteContext ctx(paste_count, times, ItemCounts(), false);
4755 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4756 (*i)->paste (position, *cut_buffer, ctx);
4760 commit_reversible_command ();
4764 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4766 if (regions.empty ()) {
4770 boost::shared_ptr<Playlist> playlist;
4771 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4772 RegionSelection foo;
4774 framepos_t const start_frame = regions.start ();
4775 framepos_t const end_frame = regions.end_frame ();
4776 framecnt_t const gap = end_frame - start_frame;
4778 begin_reversible_command (Operations::duplicate_region);
4780 selection->clear_regions ();
4782 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4784 boost::shared_ptr<Region> r ((*i)->region());
4786 TimeAxisView& tv = (*i)->get_time_axis_view();
4787 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4788 latest_regionviews.clear ();
4789 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4791 framepos_t const position = end_frame + (r->first_frame() - start_frame);
4792 playlist = (*i)->region()->playlist();
4793 playlist->clear_changes ();
4794 playlist->duplicate (r, position, gap, times);
4795 _session->add_command(new StatefulDiffCommand (playlist));
4799 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4803 selection->set (foo);
4806 commit_reversible_command ();
4810 Editor::duplicate_selection (float times)
4812 if (selection->time.empty() || selection->tracks.empty()) {
4816 boost::shared_ptr<Playlist> playlist;
4817 vector<boost::shared_ptr<Region> > new_regions;
4818 vector<boost::shared_ptr<Region> >::iterator ri;
4820 create_region_from_selection (new_regions);
4822 if (new_regions.empty()) {
4826 ri = new_regions.begin();
4828 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4829 bool in_command = false;
4831 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4832 if ((playlist = (*i)->playlist()) == 0) {
4835 playlist->clear_changes ();
4837 if (clicked_selection) {
4838 end = selection->time[clicked_selection].end;
4840 end = selection->time.end_frame();
4842 playlist->duplicate (*ri, end, times);
4845 begin_reversible_command (_("duplicate selection"));
4848 _session->add_command (new StatefulDiffCommand (playlist));
4851 if (ri == new_regions.end()) {
4857 commit_reversible_command ();
4861 /** Reset all selected points to the relevant default value */
4863 Editor::reset_point_selection ()
4865 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4866 ARDOUR::AutomationList::iterator j = (*i)->model ();
4867 (*j)->value = (*i)->line().the_list()->default_value ();
4872 Editor::center_playhead ()
4874 float const page = _visible_canvas_width * samples_per_pixel;
4875 center_screen_internal (playhead_cursor->current_frame (), page);
4879 Editor::center_edit_point ()
4881 float const page = _visible_canvas_width * samples_per_pixel;
4882 center_screen_internal (get_preferred_edit_position(), page);
4885 /** Caller must begin and commit a reversible command */
4887 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4889 playlist->clear_changes ();
4891 _session->add_command (new StatefulDiffCommand (playlist));
4895 Editor::nudge_track (bool use_edit, bool forwards)
4897 boost::shared_ptr<Playlist> playlist;
4898 framepos_t distance;
4899 framepos_t next_distance;
4903 start = get_preferred_edit_position();
4908 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4912 if (selection->tracks.empty()) {
4916 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4917 bool in_command = false;
4919 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4921 if ((playlist = (*i)->playlist()) == 0) {
4925 playlist->clear_changes ();
4926 playlist->clear_owned_changes ();
4928 playlist->nudge_after (start, distance, forwards);
4931 begin_reversible_command (_("nudge track"));
4934 vector<Command*> cmds;
4936 playlist->rdiff (cmds);
4937 _session->add_commands (cmds);
4939 _session->add_command (new StatefulDiffCommand (playlist));
4943 commit_reversible_command ();
4948 Editor::remove_last_capture ()
4950 vector<string> choices;
4957 if (Config->get_verify_remove_last_capture()) {
4958 prompt = _("Do you really want to destroy the last capture?"
4959 "\n(This is destructive and cannot be undone)");
4961 choices.push_back (_("No, do nothing."));
4962 choices.push_back (_("Yes, destroy it."));
4964 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4966 if (prompter.run () == 1) {
4967 _session->remove_last_capture ();
4968 _regions->redisplay ();
4972 _session->remove_last_capture();
4973 _regions->redisplay ();
4978 Editor::normalize_region ()
4984 RegionSelection rs = get_regions_from_selection_and_entered ();
4990 NormalizeDialog dialog (rs.size() > 1);
4992 if (dialog.run () == RESPONSE_CANCEL) {
4996 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4999 /* XXX: should really only count audio regions here */
5000 int const regions = rs.size ();
5002 /* Make a list of the selected audio regions' maximum amplitudes, and also
5003 obtain the maximum amplitude of them all.
5005 list<double> max_amps;
5007 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5008 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5010 dialog.descend (1.0 / regions);
5011 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5014 /* the user cancelled the operation */
5018 max_amps.push_back (a);
5019 max_amp = max (max_amp, a);
5024 list<double>::const_iterator a = max_amps.begin ();
5025 bool in_command = false;
5027 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5028 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5033 arv->region()->clear_changes ();
5035 double const amp = dialog.normalize_individually() ? *a : max_amp;
5037 arv->audio_region()->normalize (amp, dialog.target ());
5040 begin_reversible_command (_("normalize"));
5043 _session->add_command (new StatefulDiffCommand (arv->region()));
5049 commit_reversible_command ();
5055 Editor::reset_region_scale_amplitude ()
5061 RegionSelection rs = get_regions_from_selection_and_entered ();
5067 bool in_command = false;
5069 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5070 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5073 arv->region()->clear_changes ();
5074 arv->audio_region()->set_scale_amplitude (1.0f);
5077 begin_reversible_command ("reset gain");
5080 _session->add_command (new StatefulDiffCommand (arv->region()));
5084 commit_reversible_command ();
5089 Editor::adjust_region_gain (bool up)
5091 RegionSelection rs = get_regions_from_selection_and_entered ();
5093 if (!_session || rs.empty()) {
5097 bool in_command = false;
5099 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5100 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5105 arv->region()->clear_changes ();
5107 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5115 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5118 begin_reversible_command ("adjust region gain");
5121 _session->add_command (new StatefulDiffCommand (arv->region()));
5125 commit_reversible_command ();
5131 Editor::reverse_region ()
5137 Reverse rev (*_session);
5138 apply_filter (rev, _("reverse regions"));
5142 Editor::strip_region_silence ()
5148 RegionSelection rs = get_regions_from_selection_and_entered ();
5154 std::list<RegionView*> audio_only;
5156 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5157 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5159 audio_only.push_back (arv);
5163 assert (!audio_only.empty());
5165 StripSilenceDialog d (_session, audio_only);
5166 int const r = d.run ();
5170 if (r == Gtk::RESPONSE_OK) {
5171 ARDOUR::AudioIntervalMap silences;
5172 d.silences (silences);
5173 StripSilence s (*_session, silences, d.fade_length());
5174 apply_filter (s, _("strip silence"), &d);
5179 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5181 Evoral::Sequence<Evoral::Beats>::Notes selected;
5182 mrv.selection_as_notelist (selected, true);
5184 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5185 v.push_back (selected);
5187 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5188 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5190 return op (mrv.midi_region()->model(), pos_beats, v);
5194 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5200 bool in_command = false;
5202 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5203 RegionSelection::const_iterator tmp = r;
5206 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5209 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5212 begin_reversible_command (op.name ());
5216 _session->add_command (cmd);
5224 commit_reversible_command ();
5229 Editor::fork_region ()
5231 RegionSelection rs = get_regions_from_selection_and_entered ();
5237 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5238 bool in_command = false;
5242 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5243 RegionSelection::iterator tmp = r;
5246 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5250 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5251 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5252 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5255 begin_reversible_command (_("Fork Region(s)"));
5258 playlist->clear_changes ();
5259 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5260 _session->add_command(new StatefulDiffCommand (playlist));
5262 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5270 commit_reversible_command ();
5275 Editor::quantize_region ()
5278 quantize_regions(get_regions_from_selection_and_entered ());
5283 Editor::quantize_regions (const RegionSelection& rs)
5285 if (rs.n_midi_regions() == 0) {
5289 if (!quantize_dialog) {
5290 quantize_dialog = new QuantizeDialog (*this);
5293 quantize_dialog->present ();
5294 const int r = quantize_dialog->run ();
5295 quantize_dialog->hide ();
5297 if (r == Gtk::RESPONSE_OK) {
5298 Quantize quant (quantize_dialog->snap_start(),
5299 quantize_dialog->snap_end(),
5300 quantize_dialog->start_grid_size(),
5301 quantize_dialog->end_grid_size(),
5302 quantize_dialog->strength(),
5303 quantize_dialog->swing(),
5304 quantize_dialog->threshold());
5306 apply_midi_note_edit_op (quant, rs);
5311 Editor::legatize_region (bool shrink_only)
5314 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5319 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5321 if (rs.n_midi_regions() == 0) {
5325 Legatize legatize(shrink_only);
5326 apply_midi_note_edit_op (legatize, rs);
5330 Editor::transform_region ()
5333 transform_regions(get_regions_from_selection_and_entered ());
5338 Editor::transform_regions (const RegionSelection& rs)
5340 if (rs.n_midi_regions() == 0) {
5344 TransformDialog* td = new TransformDialog();
5347 const int r = td->run();
5350 if (r == Gtk::RESPONSE_OK) {
5351 Transform transform(td->get());
5352 apply_midi_note_edit_op(transform, rs);
5357 Editor::insert_patch_change (bool from_context)
5359 RegionSelection rs = get_regions_from_selection_and_entered ();
5365 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5367 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5368 there may be more than one, but the PatchChangeDialog can only offer
5369 one set of patch menus.
5371 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5373 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5374 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5376 if (d.run() == RESPONSE_CANCEL) {
5380 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5381 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5383 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5384 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5391 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5393 RegionSelection rs = get_regions_from_selection_and_entered ();
5399 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5400 bool in_command = false;
5405 int const N = rs.size ();
5407 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5408 RegionSelection::iterator tmp = r;
5411 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5413 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5416 progress->descend (1.0 / N);
5419 if (arv->audio_region()->apply (filter, progress) == 0) {
5421 playlist->clear_changes ();
5422 playlist->clear_owned_changes ();
5424 if (filter.results.empty ()) {
5426 /* no regions returned; remove the old one */
5427 playlist->remove_region (arv->region ());
5431 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5433 /* first region replaces the old one */
5434 playlist->replace_region (arv->region(), *res, (*res)->position());
5438 while (res != filter.results.end()) {
5439 playlist->add_region (*res, (*res)->position());
5444 /* We might have removed regions, which alters other regions' layering_index,
5445 so we need to do a recursive diff here.
5449 begin_reversible_command (command);
5452 vector<Command*> cmds;
5453 playlist->rdiff (cmds);
5454 _session->add_commands (cmds);
5456 _session->add_command(new StatefulDiffCommand (playlist));
5460 progress->ascend ();
5469 commit_reversible_command ();
5474 Editor::external_edit_region ()
5480 Editor::reset_region_gain_envelopes ()
5482 RegionSelection rs = get_regions_from_selection_and_entered ();
5484 if (!_session || rs.empty()) {
5488 bool in_command = false;
5490 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5491 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5493 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5494 XMLNode& before (alist->get_state());
5496 arv->audio_region()->set_default_envelope ();
5499 begin_reversible_command (_("reset region gain"));
5502 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5507 commit_reversible_command ();
5512 Editor::set_region_gain_visibility (RegionView* rv)
5514 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5516 arv->update_envelope_visibility();
5521 Editor::set_gain_envelope_visibility ()
5527 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5528 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5530 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5536 Editor::toggle_gain_envelope_active ()
5538 if (_ignore_region_action) {
5542 RegionSelection rs = get_regions_from_selection_and_entered ();
5544 if (!_session || rs.empty()) {
5548 bool in_command = false;
5550 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5551 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5553 arv->region()->clear_changes ();
5554 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5557 begin_reversible_command (_("region gain envelope active"));
5560 _session->add_command (new StatefulDiffCommand (arv->region()));
5565 commit_reversible_command ();
5570 Editor::toggle_region_lock ()
5572 if (_ignore_region_action) {
5576 RegionSelection rs = get_regions_from_selection_and_entered ();
5578 if (!_session || rs.empty()) {
5582 begin_reversible_command (_("toggle region lock"));
5584 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5585 (*i)->region()->clear_changes ();
5586 (*i)->region()->set_locked (!(*i)->region()->locked());
5587 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5590 commit_reversible_command ();
5594 Editor::toggle_region_video_lock ()
5596 if (_ignore_region_action) {
5600 RegionSelection rs = get_regions_from_selection_and_entered ();
5602 if (!_session || rs.empty()) {
5606 begin_reversible_command (_("Toggle Video Lock"));
5608 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5609 (*i)->region()->clear_changes ();
5610 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5611 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5614 commit_reversible_command ();
5618 Editor::toggle_region_lock_style ()
5620 if (_ignore_region_action) {
5624 RegionSelection rs = get_regions_from_selection_and_entered ();
5626 if (!_session || rs.empty()) {
5630 begin_reversible_command (_("region lock style"));
5632 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5633 (*i)->region()->clear_changes ();
5634 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5635 (*i)->region()->set_position_lock_style (ns);
5636 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5639 commit_reversible_command ();
5643 Editor::toggle_opaque_region ()
5645 if (_ignore_region_action) {
5649 RegionSelection rs = get_regions_from_selection_and_entered ();
5651 if (!_session || rs.empty()) {
5655 begin_reversible_command (_("change region opacity"));
5657 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5658 (*i)->region()->clear_changes ();
5659 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5660 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5663 commit_reversible_command ();
5667 Editor::toggle_record_enable ()
5669 bool new_state = false;
5671 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5672 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5675 if (!rtav->is_track())
5679 new_state = !rtav->track()->record_enabled();
5683 rtav->track()->set_record_enabled (new_state, this);
5688 Editor::toggle_solo ()
5690 bool new_state = false;
5692 boost::shared_ptr<RouteList> rl (new RouteList);
5694 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5695 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5702 new_state = !rtav->route()->soloed ();
5706 rl->push_back (rtav->route());
5709 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5713 Editor::toggle_mute ()
5715 bool new_state = false;
5717 boost::shared_ptr<RouteList> rl (new RouteList);
5719 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5720 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5727 new_state = !rtav->route()->muted();
5731 rl->push_back (rtav->route());
5734 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5738 Editor::toggle_solo_isolate ()
5744 Editor::fade_range ()
5746 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5748 begin_reversible_command (_("fade range"));
5750 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5751 (*i)->fade_range (selection->time);
5754 commit_reversible_command ();
5759 Editor::set_fade_length (bool in)
5761 RegionSelection rs = get_regions_from_selection_and_entered ();
5767 /* we need a region to measure the offset from the start */
5769 RegionView* rv = rs.front ();
5771 framepos_t pos = get_preferred_edit_position();
5775 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5776 /* edit point is outside the relevant region */
5781 if (pos <= rv->region()->position()) {
5785 len = pos - rv->region()->position();
5786 cmd = _("set fade in length");
5788 if (pos >= rv->region()->last_frame()) {
5792 len = rv->region()->last_frame() - pos;
5793 cmd = _("set fade out length");
5796 bool in_command = false;
5798 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5799 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5805 boost::shared_ptr<AutomationList> alist;
5807 alist = tmp->audio_region()->fade_in();
5809 alist = tmp->audio_region()->fade_out();
5812 XMLNode &before = alist->get_state();
5815 tmp->audio_region()->set_fade_in_length (len);
5816 tmp->audio_region()->set_fade_in_active (true);
5818 tmp->audio_region()->set_fade_out_length (len);
5819 tmp->audio_region()->set_fade_out_active (true);
5823 begin_reversible_command (cmd);
5826 XMLNode &after = alist->get_state();
5827 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5831 commit_reversible_command ();
5836 Editor::set_fade_in_shape (FadeShape shape)
5838 RegionSelection rs = get_regions_from_selection_and_entered ();
5843 bool in_command = false;
5845 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5846 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5852 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5853 XMLNode &before = alist->get_state();
5855 tmp->audio_region()->set_fade_in_shape (shape);
5858 begin_reversible_command (_("set fade in shape"));
5861 XMLNode &after = alist->get_state();
5862 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5866 commit_reversible_command ();
5871 Editor::set_fade_out_shape (FadeShape shape)
5873 RegionSelection rs = get_regions_from_selection_and_entered ();
5878 bool in_command = false;
5880 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5881 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5887 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5888 XMLNode &before = alist->get_state();
5890 tmp->audio_region()->set_fade_out_shape (shape);
5893 begin_reversible_command (_("set fade out shape"));
5896 XMLNode &after = alist->get_state();
5897 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5901 commit_reversible_command ();
5906 Editor::set_fade_in_active (bool yn)
5908 RegionSelection rs = get_regions_from_selection_and_entered ();
5913 bool in_command = false;
5915 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5916 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5923 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5925 ar->clear_changes ();
5926 ar->set_fade_in_active (yn);
5929 begin_reversible_command (_("set fade in active"));
5932 _session->add_command (new StatefulDiffCommand (ar));
5936 commit_reversible_command ();
5941 Editor::set_fade_out_active (bool yn)
5943 RegionSelection rs = get_regions_from_selection_and_entered ();
5948 bool in_command = false;
5950 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5951 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5957 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5959 ar->clear_changes ();
5960 ar->set_fade_out_active (yn);
5963 begin_reversible_command (_("set fade out active"));
5966 _session->add_command(new StatefulDiffCommand (ar));
5970 commit_reversible_command ();
5975 Editor::toggle_region_fades (int dir)
5977 if (_ignore_region_action) {
5981 boost::shared_ptr<AudioRegion> ar;
5984 RegionSelection rs = get_regions_from_selection_and_entered ();
5990 RegionSelection::iterator i;
5991 for (i = rs.begin(); i != rs.end(); ++i) {
5992 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5994 yn = ar->fade_out_active ();
5996 yn = ar->fade_in_active ();
6002 if (i == rs.end()) {
6006 /* XXX should this undo-able? */
6007 bool in_command = false;
6009 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6010 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6013 ar->clear_changes ();
6015 if (dir == 1 || dir == 0) {
6016 ar->set_fade_in_active (!yn);
6019 if (dir == -1 || dir == 0) {
6020 ar->set_fade_out_active (!yn);
6023 begin_reversible_command (_("toggle fade active"));
6026 _session->add_command(new StatefulDiffCommand (ar));
6030 commit_reversible_command ();
6035 /** Update region fade visibility after its configuration has been changed */
6037 Editor::update_region_fade_visibility ()
6039 bool _fade_visibility = _session->config.get_show_region_fades ();
6041 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6042 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6044 if (_fade_visibility) {
6045 v->audio_view()->show_all_fades ();
6047 v->audio_view()->hide_all_fades ();
6054 Editor::set_edit_point ()
6059 if (!mouse_frame (where, ignored)) {
6065 if (selection->markers.empty()) {
6067 mouse_add_new_marker (where);
6072 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6075 loc->move_to (where);
6081 Editor::set_playhead_cursor ()
6083 if (entered_marker) {
6084 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6089 if (!mouse_frame (where, ignored)) {
6096 _session->request_locate (where, _session->transport_rolling());
6100 if (UIConfiguration::instance().get_follow_edits()) {
6101 cancel_time_selection();
6106 Editor::split_region ()
6108 if (_drags->active ()) {
6112 //if a range is selected, separate it
6113 if ( !selection->time.empty()) {
6114 separate_regions_between (selection->time);
6118 //if no range was selected, try to find some regions to split
6119 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6121 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6123 framepos_t where = get_preferred_edit_position ();
6129 split_regions_at (where, rs);
6133 struct EditorOrderRouteSorter {
6134 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6135 return a->order_key () < b->order_key ();
6140 Editor::select_next_route()
6142 if (selection->tracks.empty()) {
6143 selection->set (track_views.front());
6147 TimeAxisView* current = selection->tracks.front();
6151 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6152 if (*i == current) {
6154 if (i != track_views.end()) {
6157 current = (*(track_views.begin()));
6158 //selection->set (*(track_views.begin()));
6163 rui = dynamic_cast<RouteUI *>(current);
6164 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6166 selection->set(current);
6168 ensure_time_axis_view_is_visible (*current, false);
6172 Editor::select_prev_route()
6174 if (selection->tracks.empty()) {
6175 selection->set (track_views.front());
6179 TimeAxisView* current = selection->tracks.front();
6183 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6184 if (*i == current) {
6186 if (i != track_views.rend()) {
6189 current = *(track_views.rbegin());
6194 rui = dynamic_cast<RouteUI *>(current);
6195 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6197 selection->set (current);
6199 ensure_time_axis_view_is_visible (*current, false);
6203 Editor::set_loop_from_selection (bool play)
6205 if (_session == 0) {
6209 framepos_t start, end;
6210 if (!get_selection_extents ( start, end))
6213 set_loop_range (start, end, _("set loop range from selection"));
6216 _session->request_play_loop (true, true);
6221 Editor::set_loop_from_region (bool play)
6223 framepos_t start, end;
6224 if (!get_selection_extents ( start, end))
6227 set_loop_range (start, end, _("set loop range from region"));
6230 _session->request_locate (start, true);
6231 _session->request_play_loop (true);
6236 Editor::set_punch_from_selection ()
6238 if (_session == 0) {
6242 framepos_t start, end;
6243 if (!get_selection_extents ( start, end))
6246 set_punch_range (start, end, _("set punch range from selection"));
6250 Editor::set_session_extents_from_selection ()
6252 if (_session == 0) {
6256 framepos_t start, end;
6257 if (!get_selection_extents ( start, end))
6261 if ((loc = _session->locations()->session_range_location()) == 0) {
6262 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6264 XMLNode &before = loc->get_state();
6266 _session->set_session_extents ( start, end );
6268 XMLNode &after = loc->get_state();
6270 begin_reversible_command (_("set session start/end from selection"));
6272 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6274 commit_reversible_command ();
6279 Editor::set_punch_start_from_edit_point ()
6283 framepos_t start = 0;
6284 framepos_t end = max_framepos;
6286 //use the existing punch end, if any
6287 Location* tpl = transport_punch_location();
6292 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6293 start = _session->audible_frame();
6295 start = get_preferred_edit_position();
6298 //snap the selection start/end
6301 //if there's not already a sensible selection endpoint, go "forever"
6302 if ( start > end ) {
6306 set_punch_range (start, end, _("set punch start from EP"));
6312 Editor::set_punch_end_from_edit_point ()
6316 framepos_t start = 0;
6317 framepos_t end = max_framepos;
6319 //use the existing punch start, if any
6320 Location* tpl = transport_punch_location();
6322 start = tpl->start();
6325 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6326 end = _session->audible_frame();
6328 end = get_preferred_edit_position();
6331 //snap the selection start/end
6334 set_punch_range (start, end, _("set punch end from EP"));
6340 Editor::set_loop_start_from_edit_point ()
6344 framepos_t start = 0;
6345 framepos_t end = max_framepos;
6347 //use the existing loop end, if any
6348 Location* tpl = transport_loop_location();
6353 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6354 start = _session->audible_frame();
6356 start = get_preferred_edit_position();
6359 //snap the selection start/end
6362 //if there's not already a sensible selection endpoint, go "forever"
6363 if ( start > end ) {
6367 set_loop_range (start, end, _("set loop start from EP"));
6373 Editor::set_loop_end_from_edit_point ()
6377 framepos_t start = 0;
6378 framepos_t end = max_framepos;
6380 //use the existing loop start, if any
6381 Location* tpl = transport_loop_location();
6383 start = tpl->start();
6386 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6387 end = _session->audible_frame();
6389 end = get_preferred_edit_position();
6392 //snap the selection start/end
6395 set_loop_range (start, end, _("set loop end from EP"));
6400 Editor::set_punch_from_region ()
6402 framepos_t start, end;
6403 if (!get_selection_extents ( start, end))
6406 set_punch_range (start, end, _("set punch range from region"));
6410 Editor::pitch_shift_region ()
6412 RegionSelection rs = get_regions_from_selection_and_entered ();
6414 RegionSelection audio_rs;
6415 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6416 if (dynamic_cast<AudioRegionView*> (*i)) {
6417 audio_rs.push_back (*i);
6421 if (audio_rs.empty()) {
6425 pitch_shift (audio_rs, 1.2);
6429 Editor::transpose_region ()
6431 RegionSelection rs = get_regions_from_selection_and_entered ();
6433 list<MidiRegionView*> midi_region_views;
6434 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6435 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6437 midi_region_views.push_back (mrv);
6442 int const r = d.run ();
6443 if (r != RESPONSE_ACCEPT) {
6447 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6448 (*i)->midi_region()->transpose (d.semitones ());
6453 Editor::set_tempo_from_region ()
6455 RegionSelection rs = get_regions_from_selection_and_entered ();
6457 if (!_session || rs.empty()) {
6461 RegionView* rv = rs.front();
6463 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6467 Editor::use_range_as_bar ()
6469 framepos_t start, end;
6470 if (get_edit_op_range (start, end)) {
6471 define_one_bar (start, end);
6476 Editor::define_one_bar (framepos_t start, framepos_t end)
6478 framepos_t length = end - start;
6480 const Meter& m (_session->tempo_map().meter_at (start));
6482 /* length = 1 bar */
6484 /* now we want frames per beat.
6485 we have frames per bar, and beats per bar, so ...
6488 /* XXXX METER MATH */
6490 double frames_per_beat = length / m.divisions_per_bar();
6492 /* beats per minute = */
6494 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6496 /* now decide whether to:
6498 (a) set global tempo
6499 (b) add a new tempo marker
6503 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6505 bool do_global = false;
6507 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6509 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6510 at the start, or create a new marker
6513 vector<string> options;
6514 options.push_back (_("Cancel"));
6515 options.push_back (_("Add new marker"));
6516 options.push_back (_("Set global tempo"));
6519 _("Define one bar"),
6520 _("Do you want to set the global tempo or add a new tempo marker?"),
6524 c.set_default_response (2);
6540 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6541 if the marker is at the region starter, change it, otherwise add
6546 begin_reversible_command (_("set tempo from region"));
6547 XMLNode& before (_session->tempo_map().get_state());
6550 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6551 } else if (t.frame() == start) {
6552 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6554 Timecode::BBT_Time bbt;
6555 _session->tempo_map().bbt_time (start, bbt);
6556 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6559 XMLNode& after (_session->tempo_map().get_state());
6561 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6562 commit_reversible_command ();
6566 Editor::split_region_at_transients ()
6568 AnalysisFeatureList positions;
6570 RegionSelection rs = get_regions_from_selection_and_entered ();
6572 if (!_session || rs.empty()) {
6576 begin_reversible_command (_("split regions"));
6578 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6580 RegionSelection::iterator tmp;
6585 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6587 if (ar && (ar->get_transients (positions) == 0)) {
6588 split_region_at_points ((*i)->region(), positions, true);
6595 commit_reversible_command ();
6600 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6602 bool use_rhythmic_rodent = false;
6604 boost::shared_ptr<Playlist> pl = r->playlist();
6606 list<boost::shared_ptr<Region> > new_regions;
6612 if (positions.empty()) {
6617 if (positions.size() > 20 && can_ferret) {
6618 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);
6619 MessageDialog msg (msgstr,
6622 Gtk::BUTTONS_OK_CANCEL);
6625 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6626 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6628 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6631 msg.set_title (_("Excessive split?"));
6634 int response = msg.run();
6640 case RESPONSE_APPLY:
6641 use_rhythmic_rodent = true;
6648 if (use_rhythmic_rodent) {
6649 show_rhythm_ferret ();
6653 AnalysisFeatureList::const_iterator x;
6655 pl->clear_changes ();
6656 pl->clear_owned_changes ();
6658 x = positions.begin();
6660 if (x == positions.end()) {
6665 pl->remove_region (r);
6669 while (x != positions.end()) {
6671 /* deal with positons that are out of scope of present region bounds */
6672 if (*x <= 0 || *x > r->length()) {
6677 /* file start = original start + how far we from the initial position ?
6680 framepos_t file_start = r->start() + pos;
6682 /* length = next position - current position
6685 framepos_t len = (*x) - pos;
6687 /* XXX we do we really want to allow even single-sample regions?
6688 shouldn't we have some kind of lower limit on region size?
6697 if (RegionFactory::region_name (new_name, r->name())) {
6701 /* do NOT announce new regions 1 by one, just wait till they are all done */
6705 plist.add (ARDOUR::Properties::start, file_start);
6706 plist.add (ARDOUR::Properties::length, len);
6707 plist.add (ARDOUR::Properties::name, new_name);
6708 plist.add (ARDOUR::Properties::layer, 0);
6710 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6711 /* because we set annouce to false, manually add the new region to the
6714 RegionFactory::map_add (nr);
6716 pl->add_region (nr, r->position() + pos);
6719 new_regions.push_front(nr);
6728 RegionFactory::region_name (new_name, r->name());
6730 /* Add the final region */
6733 plist.add (ARDOUR::Properties::start, r->start() + pos);
6734 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6735 plist.add (ARDOUR::Properties::name, new_name);
6736 plist.add (ARDOUR::Properties::layer, 0);
6738 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6739 /* because we set annouce to false, manually add the new region to the
6742 RegionFactory::map_add (nr);
6743 pl->add_region (nr, r->position() + pos);
6746 new_regions.push_front(nr);
6751 /* We might have removed regions, which alters other regions' layering_index,
6752 so we need to do a recursive diff here.
6754 vector<Command*> cmds;
6756 _session->add_commands (cmds);
6758 _session->add_command (new StatefulDiffCommand (pl));
6762 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6763 set_selected_regionview_from_region_list ((*i), Selection::Add);
6769 Editor::place_transient()
6775 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6781 framepos_t where = get_preferred_edit_position();
6783 begin_reversible_command (_("place transient"));
6785 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6786 framepos_t position = (*r)->region()->position();
6787 (*r)->region()->add_transient(where - position);
6790 commit_reversible_command ();
6794 Editor::remove_transient(ArdourCanvas::Item* item)
6800 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6803 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6804 _arv->remove_transient (*(float*) _line->get_data ("position"));
6808 Editor::snap_regions_to_grid ()
6810 list <boost::shared_ptr<Playlist > > used_playlists;
6812 RegionSelection rs = get_regions_from_selection_and_entered ();
6814 if (!_session || rs.empty()) {
6818 begin_reversible_command (_("snap regions to grid"));
6820 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6822 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6824 if (!pl->frozen()) {
6825 /* we haven't seen this playlist before */
6827 /* remember used playlists so we can thaw them later */
6828 used_playlists.push_back(pl);
6832 framepos_t start_frame = (*r)->region()->first_frame ();
6833 snap_to (start_frame);
6834 (*r)->region()->set_position (start_frame);
6837 while (used_playlists.size() > 0) {
6838 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6840 used_playlists.pop_front();
6843 commit_reversible_command ();
6847 Editor::close_region_gaps ()
6849 list <boost::shared_ptr<Playlist > > used_playlists;
6851 RegionSelection rs = get_regions_from_selection_and_entered ();
6853 if (!_session || rs.empty()) {
6857 Dialog dialog (_("Close Region Gaps"));
6860 table.set_spacings (12);
6861 table.set_border_width (12);
6862 Label* l = manage (left_aligned_label (_("Crossfade length")));
6863 table.attach (*l, 0, 1, 0, 1);
6865 SpinButton spin_crossfade (1, 0);
6866 spin_crossfade.set_range (0, 15);
6867 spin_crossfade.set_increments (1, 1);
6868 spin_crossfade.set_value (5);
6869 table.attach (spin_crossfade, 1, 2, 0, 1);
6871 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6873 l = manage (left_aligned_label (_("Pull-back length")));
6874 table.attach (*l, 0, 1, 1, 2);
6876 SpinButton spin_pullback (1, 0);
6877 spin_pullback.set_range (0, 100);
6878 spin_pullback.set_increments (1, 1);
6879 spin_pullback.set_value(30);
6880 table.attach (spin_pullback, 1, 2, 1, 2);
6882 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6884 dialog.get_vbox()->pack_start (table);
6885 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6886 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6889 if (dialog.run () == RESPONSE_CANCEL) {
6893 framepos_t crossfade_len = spin_crossfade.get_value();
6894 framepos_t pull_back_frames = spin_pullback.get_value();
6896 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6897 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6899 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6901 begin_reversible_command (_("close region gaps"));
6904 boost::shared_ptr<Region> last_region;
6906 rs.sort_by_position_and_track();
6908 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6910 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6912 if (!pl->frozen()) {
6913 /* we haven't seen this playlist before */
6915 /* remember used playlists so we can thaw them later */
6916 used_playlists.push_back(pl);
6920 framepos_t position = (*r)->region()->position();
6922 if (idx == 0 || position < last_region->position()){
6923 last_region = (*r)->region();
6928 (*r)->region()->trim_front( (position - pull_back_frames));
6929 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6931 last_region = (*r)->region();
6936 while (used_playlists.size() > 0) {
6937 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6939 used_playlists.pop_front();
6942 commit_reversible_command ();
6946 Editor::tab_to_transient (bool forward)
6948 AnalysisFeatureList positions;
6950 RegionSelection rs = get_regions_from_selection_and_entered ();
6956 framepos_t pos = _session->audible_frame ();
6958 if (!selection->tracks.empty()) {
6960 /* don't waste time searching for transients in duplicate playlists.
6963 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6965 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6967 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6970 boost::shared_ptr<Track> tr = rtv->track();
6972 boost::shared_ptr<Playlist> pl = tr->playlist ();
6974 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6977 positions.push_back (result);
6990 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6991 (*r)->region()->get_transients (positions);
6995 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6998 AnalysisFeatureList::iterator x;
7000 for (x = positions.begin(); x != positions.end(); ++x) {
7006 if (x != positions.end ()) {
7007 _session->request_locate (*x);
7011 AnalysisFeatureList::reverse_iterator x;
7013 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7019 if (x != positions.rend ()) {
7020 _session->request_locate (*x);
7026 Editor::playhead_forward_to_grid ()
7032 framepos_t pos = playhead_cursor->current_frame ();
7033 if (pos < max_framepos - 1) {
7035 snap_to_internal (pos, RoundUpAlways, false);
7036 _session->request_locate (pos);
7042 Editor::playhead_backward_to_grid ()
7048 framepos_t pos = playhead_cursor->current_frame ();
7051 snap_to_internal (pos, RoundDownAlways, false);
7052 _session->request_locate (pos);
7057 Editor::set_track_height (Height h)
7059 TrackSelection& ts (selection->tracks);
7061 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7062 (*x)->set_height_enum (h);
7067 Editor::toggle_tracks_active ()
7069 TrackSelection& ts (selection->tracks);
7071 bool target = false;
7077 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7078 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7082 target = !rtv->_route->active();
7085 rtv->_route->set_active (target, this);
7091 Editor::remove_tracks ()
7093 /* this will delete GUI objects that may be the subject of an event
7094 handler in which this method is called. Defer actual deletion to the
7095 next idle callback, when all event handling is finished.
7097 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7101 Editor::idle_remove_tracks ()
7104 return false; /* do not call again */
7108 Editor::_remove_tracks ()
7110 TrackSelection& ts (selection->tracks);
7116 vector<string> choices;
7120 const char* trackstr;
7122 vector<boost::shared_ptr<Route> > routes;
7123 bool special_bus = false;
7125 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7126 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7130 if (rtv->is_track()) {
7135 routes.push_back (rtv->_route);
7137 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7142 if (special_bus && !Config->get_allow_special_bus_removal()) {
7143 MessageDialog msg (_("That would be bad news ...."),
7147 msg.set_secondary_text (string_compose (_(
7148 "Removing the master or monitor bus is such a bad idea\n\
7149 that %1 is not going to allow it.\n\
7151 If you really want to do this sort of thing\n\
7152 edit your ardour.rc file to set the\n\
7153 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7160 if (ntracks + nbusses == 0) {
7164 trackstr = P_("track", "tracks", ntracks);
7165 busstr = P_("bus", "busses", nbusses);
7169 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7170 "(You may also lose the playlists associated with the %2)\n\n"
7171 "This action cannot be undone, and the session file will be overwritten!"),
7172 ntracks, trackstr, nbusses, busstr);
7174 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7175 "(You may also lose the playlists associated with the %2)\n\n"
7176 "This action cannot be undone, and the session file will be overwritten!"),
7179 } else if (nbusses) {
7180 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7181 "This action cannot be undone, and the session file will be overwritten"),
7185 choices.push_back (_("No, do nothing."));
7186 if (ntracks + nbusses > 1) {
7187 choices.push_back (_("Yes, remove them."));
7189 choices.push_back (_("Yes, remove it."));
7194 title = string_compose (_("Remove %1"), trackstr);
7196 title = string_compose (_("Remove %1"), busstr);
7199 Choice prompter (title, prompt, choices);
7201 if (prompter.run () != 1) {
7206 Session::StateProtector sp (_session);
7207 DisplaySuspender ds;
7208 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7209 _session->remove_route (*x);
7215 Editor::do_insert_time ()
7217 if (selection->tracks.empty()) {
7221 InsertRemoveTimeDialog d (*this);
7222 int response = d.run ();
7224 if (response != RESPONSE_OK) {
7228 if (d.distance() == 0) {
7232 InsertTimeOption opt = d.intersected_region_action ();
7235 get_preferred_edit_position(),
7241 d.move_glued_markers(),
7242 d.move_locked_markers(),
7248 Editor::insert_time (
7249 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7250 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7254 if (Config->get_edit_mode() == Lock) {
7257 bool in_command = false;
7259 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7261 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7265 /* don't operate on any playlist more than once, which could
7266 * happen if "all playlists" is enabled, but there is more
7267 * than 1 track using playlists "from" a given track.
7270 set<boost::shared_ptr<Playlist> > pl;
7272 if (all_playlists) {
7273 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7274 if (rtav && rtav->track ()) {
7275 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7276 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7281 if ((*x)->playlist ()) {
7282 pl.insert ((*x)->playlist ());
7286 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7288 (*i)->clear_changes ();
7289 (*i)->clear_owned_changes ();
7291 if (opt == SplitIntersected) {
7295 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7298 begin_reversible_command (_("insert time"));
7301 vector<Command*> cmds;
7303 _session->add_commands (cmds);
7305 _session->add_command (new StatefulDiffCommand (*i));
7309 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7312 begin_reversible_command (_("insert time"));
7315 rtav->route ()->shift (pos, frames);
7322 XMLNode& before (_session->locations()->get_state());
7323 Locations::LocationList copy (_session->locations()->list());
7325 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7327 Locations::LocationList::const_iterator tmp;
7329 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7330 bool const was_locked = (*i)->locked ();
7331 if (locked_markers_too) {
7335 if ((*i)->start() >= pos) {
7336 // move end first, in case we're moving by more than the length of the range
7337 if (!(*i)->is_mark()) {
7338 (*i)->set_end ((*i)->end() + frames);
7340 (*i)->set_start ((*i)->start() + frames);
7352 begin_reversible_command (_("insert time"));
7355 XMLNode& after (_session->locations()->get_state());
7356 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7362 begin_reversible_command (_("insert time"));
7365 XMLNode& before (_session->tempo_map().get_state());
7366 _session->tempo_map().insert_time (pos, frames);
7367 XMLNode& after (_session->tempo_map().get_state());
7368 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7372 commit_reversible_command ();
7377 Editor::do_remove_time ()
7379 if (selection->tracks.empty()) {
7383 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7384 InsertRemoveTimeDialog d (*this, true);
7386 int response = d.run ();
7388 if (response != RESPONSE_OK) {
7392 framecnt_t distance = d.distance();
7394 if (distance == 0) {
7404 d.move_glued_markers(),
7405 d.move_locked_markers(),
7411 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7412 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7414 if (Config->get_edit_mode() == Lock) {
7415 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7418 bool in_command = false;
7420 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7422 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7426 XMLNode &before = pl->get_state();
7428 std::list<AudioRange> rl;
7429 AudioRange ar(pos, pos+frames, 0);
7432 pl->shift (pos, -frames, true, ignore_music_glue);
7435 begin_reversible_command (_("cut time"));
7438 XMLNode &after = pl->get_state();
7440 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7444 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7447 begin_reversible_command (_("cut time"));
7450 rtav->route ()->shift (pos, -frames);
7454 std::list<Location*> loc_kill_list;
7459 XMLNode& before (_session->locations()->get_state());
7460 Locations::LocationList copy (_session->locations()->list());
7462 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7463 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7465 bool const was_locked = (*i)->locked ();
7466 if (locked_markers_too) {
7470 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7471 if ((*i)->end() >= pos
7472 && (*i)->end() < pos+frames
7473 && (*i)->start() >= pos
7474 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7476 loc_kill_list.push_back(*i);
7477 } else { // only start or end is included, try to do the right thing
7478 // move start before moving end, to avoid trying to move the end to before the start
7479 // if we're removing more time than the length of the range
7480 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7481 // start is within cut
7482 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7484 } else if ((*i)->start() >= pos+frames) {
7485 // start (and thus entire range) lies beyond end of cut
7486 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7489 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7490 // end is inside cut
7491 (*i)->set_end (pos); // bring the end to the cut
7493 } else if ((*i)->end() >= pos+frames) {
7494 // end is beyond end of cut
7495 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7500 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7501 loc_kill_list.push_back(*i);
7503 } else if ((*i)->start() >= pos) {
7504 (*i)->set_start ((*i)->start() -frames);
7514 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7515 _session->locations()->remove( *i );
7520 begin_reversible_command (_("cut time"));
7523 XMLNode& after (_session->locations()->get_state());
7524 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7529 XMLNode& before (_session->tempo_map().get_state());
7531 if (_session->tempo_map().remove_time (pos, frames) ) {
7533 begin_reversible_command (_("remove time"));
7536 XMLNode& after (_session->tempo_map().get_state());
7537 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7542 commit_reversible_command ();
7547 Editor::fit_selection ()
7549 if (!selection->tracks.empty()) {
7550 fit_tracks (selection->tracks);
7554 /* no selected tracks - use tracks with selected regions */
7556 if (!selection->regions.empty()) {
7557 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7558 tvl.push_back (&(*r)->get_time_axis_view ());
7564 } else if (internal_editing()) {
7565 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7568 if (entered_track) {
7569 tvl.push_back (entered_track);
7578 Editor::fit_tracks (TrackViewList & tracks)
7580 if (tracks.empty()) {
7584 uint32_t child_heights = 0;
7585 int visible_tracks = 0;
7587 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7589 if (!(*t)->marked_for_display()) {
7593 child_heights += (*t)->effective_height() - (*t)->current_height();
7597 /* compute the per-track height from:
7599 total canvas visible height -
7600 height that will be taken by visible children of selected
7601 tracks - height of the ruler/hscroll area
7603 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7604 double first_y_pos = DBL_MAX;
7606 if (h < TimeAxisView::preset_height (HeightSmall)) {
7607 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7608 /* too small to be displayed */
7612 undo_visual_stack.push_back (current_visual_state (true));
7613 PBD::Unwinder<bool> nsv (no_save_visual, true);
7615 /* build a list of all tracks, including children */
7618 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7620 TimeAxisView::Children c = (*i)->get_child_list ();
7621 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7622 all.push_back (j->get());
7627 // find selection range.
7628 // if someone knows how to user TrackViewList::iterator for this
7630 int selected_top = -1;
7631 int selected_bottom = -1;
7633 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7634 if ((*t)->marked_for_display ()) {
7635 if (tracks.contains(*t)) {
7636 if (selected_top == -1) {
7639 selected_bottom = i;
7645 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7646 if ((*t)->marked_for_display ()) {
7647 if (tracks.contains(*t)) {
7648 (*t)->set_height (h);
7649 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7651 if (i > selected_top && i < selected_bottom) {
7652 hide_track_in_display (*t);
7659 set the controls_layout height now, because waiting for its size
7660 request signal handler will cause the vertical adjustment setting to fail
7663 controls_layout.property_height () = _full_canvas_height;
7664 vertical_adjustment.set_value (first_y_pos);
7666 redo_visual_stack.push_back (current_visual_state (true));
7668 visible_tracks_selector.set_text (_("Sel"));
7672 Editor::save_visual_state (uint32_t n)
7674 while (visual_states.size() <= n) {
7675 visual_states.push_back (0);
7678 if (visual_states[n] != 0) {
7679 delete visual_states[n];
7682 visual_states[n] = current_visual_state (true);
7687 Editor::goto_visual_state (uint32_t n)
7689 if (visual_states.size() <= n) {
7693 if (visual_states[n] == 0) {
7697 use_visual_state (*visual_states[n]);
7701 Editor::start_visual_state_op (uint32_t n)
7703 save_visual_state (n);
7705 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7707 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7708 pup->set_text (buf);
7713 Editor::cancel_visual_state_op (uint32_t n)
7715 goto_visual_state (n);
7719 Editor::toggle_region_mute ()
7721 if (_ignore_region_action) {
7725 RegionSelection rs = get_regions_from_selection_and_entered ();
7731 if (rs.size() > 1) {
7732 begin_reversible_command (_("mute regions"));
7734 begin_reversible_command (_("mute region"));
7737 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7739 (*i)->region()->playlist()->clear_changes ();
7740 (*i)->region()->set_muted (!(*i)->region()->muted ());
7741 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7745 commit_reversible_command ();
7749 Editor::combine_regions ()
7751 /* foreach track with selected regions, take all selected regions
7752 and join them into a new region containing the subregions (as a
7756 typedef set<RouteTimeAxisView*> RTVS;
7759 if (selection->regions.empty()) {
7763 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7764 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7767 tracks.insert (rtv);
7771 begin_reversible_command (_("combine regions"));
7773 vector<RegionView*> new_selection;
7775 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7778 if ((rv = (*i)->combine_regions ()) != 0) {
7779 new_selection.push_back (rv);
7783 selection->clear_regions ();
7784 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7785 selection->add (*i);
7788 commit_reversible_command ();
7792 Editor::uncombine_regions ()
7794 typedef set<RouteTimeAxisView*> RTVS;
7797 if (selection->regions.empty()) {
7801 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7802 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7805 tracks.insert (rtv);
7809 begin_reversible_command (_("uncombine regions"));
7811 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7812 (*i)->uncombine_regions ();
7815 commit_reversible_command ();
7819 Editor::toggle_midi_input_active (bool flip_others)
7822 boost::shared_ptr<RouteList> rl (new RouteList);
7824 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7825 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7831 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7834 rl->push_back (rtav->route());
7835 onoff = !mt->input_active();
7839 _session->set_exclusive_input_active (rl, onoff, flip_others);
7846 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7848 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7849 lock_dialog->get_vbox()->pack_start (*padlock);
7851 ArdourButton* b = manage (new ArdourButton);
7852 b->set_name ("lock button");
7853 b->set_text (_("Click to unlock"));
7854 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7855 lock_dialog->get_vbox()->pack_start (*b);
7857 lock_dialog->get_vbox()->show_all ();
7858 lock_dialog->set_size_request (200, 200);
7861 delete _main_menu_disabler;
7862 _main_menu_disabler = new MainMenuDisabler;
7864 lock_dialog->present ();
7870 lock_dialog->hide ();
7872 delete _main_menu_disabler;
7874 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7875 start_lock_event_timing ();
7880 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7882 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7886 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7888 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7889 Gtkmm2ext::UI::instance()->flush_pending ();
7893 Editor::bring_all_sources_into_session ()
7900 ArdourDialog w (_("Moving embedded files into session folder"));
7901 w.get_vbox()->pack_start (msg);
7904 /* flush all pending GUI events because we're about to start copying
7908 Gtkmm2ext::UI::instance()->flush_pending ();
7912 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));