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 "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_remove_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
100 #include "transform_dialog.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 (!ARDOUR_UI::config()->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() || !ARDOUR_UI::config()->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 ();
2771 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2773 if (_session->is_auditioning()) {
2774 _session->cancel_audition ();
2777 // note: some potential for creativity here, because region doesn't
2778 // have to belong to the playlist that Route is handling
2780 // bool was_soloed = route.soloed();
2782 route.set_solo (true, this);
2784 _session->request_bounded_roll (region->position(), region->position() + region->length());
2786 /* XXX how to unset the solo state ? */
2789 /** Start an audition of the first selected region */
2791 Editor::play_edit_range ()
2793 framepos_t start, end;
2795 if (get_edit_op_range (start, end)) {
2796 _session->request_bounded_roll (start, end);
2801 Editor::play_selected_region ()
2803 framepos_t start = max_framepos;
2806 RegionSelection rs = get_regions_from_selection_and_entered ();
2812 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2813 if ((*i)->region()->position() < start) {
2814 start = (*i)->region()->position();
2816 if ((*i)->region()->last_frame() + 1 > end) {
2817 end = (*i)->region()->last_frame() + 1;
2821 _session->request_bounded_roll (start, end);
2825 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2827 _session->audition_region (region);
2831 Editor::region_from_selection ()
2833 if (clicked_axisview == 0) {
2837 if (selection->time.empty()) {
2841 framepos_t start = selection->time[clicked_selection].start;
2842 framepos_t end = selection->time[clicked_selection].end;
2844 TrackViewList tracks = get_tracks_for_range_action ();
2846 framepos_t selection_cnt = end - start + 1;
2848 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2849 boost::shared_ptr<Region> current;
2850 boost::shared_ptr<Playlist> pl;
2851 framepos_t internal_start;
2854 if ((pl = (*i)->playlist()) == 0) {
2858 if ((current = pl->top_region_at (start)) == 0) {
2862 internal_start = start - current->position();
2863 RegionFactory::region_name (new_name, current->name(), true);
2867 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2868 plist.add (ARDOUR::Properties::length, selection_cnt);
2869 plist.add (ARDOUR::Properties::name, new_name);
2870 plist.add (ARDOUR::Properties::layer, 0);
2872 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2877 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2879 if (selection->time.empty() || selection->tracks.empty()) {
2883 framepos_t start, end;
2884 if (clicked_selection) {
2885 start = selection->time[clicked_selection].start;
2886 end = selection->time[clicked_selection].end;
2888 start = selection->time.start();
2889 end = selection->time.end_frame();
2892 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2893 sort_track_selection (ts);
2895 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2896 boost::shared_ptr<Region> current;
2897 boost::shared_ptr<Playlist> playlist;
2898 framepos_t internal_start;
2901 if ((playlist = (*i)->playlist()) == 0) {
2905 if ((current = playlist->top_region_at(start)) == 0) {
2909 internal_start = start - current->position();
2910 RegionFactory::region_name (new_name, current->name(), true);
2914 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2915 plist.add (ARDOUR::Properties::length, end - start + 1);
2916 plist.add (ARDOUR::Properties::name, new_name);
2918 new_regions.push_back (RegionFactory::create (current, plist));
2923 Editor::split_multichannel_region ()
2925 RegionSelection rs = get_regions_from_selection_and_entered ();
2931 vector< boost::shared_ptr<Region> > v;
2933 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2934 (*x)->region()->separate_by_channel (*_session, v);
2939 Editor::new_region_from_selection ()
2941 region_from_selection ();
2942 cancel_selection ();
2946 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2948 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2949 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2950 case Evoral::OverlapNone:
2958 * - selected tracks, or if there are none...
2959 * - tracks containing selected regions, or if there are none...
2964 Editor::get_tracks_for_range_action () const
2968 if (selection->tracks.empty()) {
2970 /* use tracks with selected regions */
2972 RegionSelection rs = selection->regions;
2974 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2975 TimeAxisView* tv = &(*i)->get_time_axis_view();
2977 if (!t.contains (tv)) {
2983 /* no regions and no tracks: use all tracks */
2989 t = selection->tracks;
2992 return t.filter_to_unique_playlists();
2996 Editor::separate_regions_between (const TimeSelection& ts)
2998 bool in_command = false;
2999 boost::shared_ptr<Playlist> playlist;
3000 RegionSelection new_selection;
3002 TrackViewList tmptracks = get_tracks_for_range_action ();
3003 sort_track_selection (tmptracks);
3005 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3007 RouteTimeAxisView* rtv;
3009 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3011 if (rtv->is_track()) {
3013 /* no edits to destructive tracks */
3015 if (rtv->track()->destructive()) {
3019 if ((playlist = rtv->playlist()) != 0) {
3021 playlist->clear_changes ();
3023 /* XXX need to consider musical time selections here at some point */
3025 double speed = rtv->track()->speed();
3028 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3030 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3031 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3033 latest_regionviews.clear ();
3035 playlist->partition ((framepos_t)((*t).start * speed),
3036 (framepos_t)((*t).end * speed), false);
3040 if (!latest_regionviews.empty()) {
3042 rtv->view()->foreach_regionview (sigc::bind (
3043 sigc::ptr_fun (add_if_covered),
3044 &(*t), &new_selection));
3047 begin_reversible_command (_("separate"));
3051 /* pick up changes to existing regions */
3053 vector<Command*> cmds;
3054 playlist->rdiff (cmds);
3055 _session->add_commands (cmds);
3057 /* pick up changes to the playlist itself (adds/removes)
3060 _session->add_command(new StatefulDiffCommand (playlist));
3069 // selection->set (new_selection);
3071 commit_reversible_command ();
3075 struct PlaylistState {
3076 boost::shared_ptr<Playlist> playlist;
3080 /** Take tracks from get_tracks_for_range_action and cut any regions
3081 * on those tracks so that the tracks are empty over the time
3085 Editor::separate_region_from_selection ()
3087 /* preferentially use *all* ranges in the time selection if we're in range mode
3088 to allow discontiguous operation, since get_edit_op_range() currently
3089 returns a single range.
3092 if (!selection->time.empty()) {
3094 separate_regions_between (selection->time);
3101 if (get_edit_op_range (start, end)) {
3103 AudioRange ar (start, end, 1);
3107 separate_regions_between (ts);
3113 Editor::separate_region_from_punch ()
3115 Location* loc = _session->locations()->auto_punch_location();
3117 separate_regions_using_location (*loc);
3122 Editor::separate_region_from_loop ()
3124 Location* loc = _session->locations()->auto_loop_location();
3126 separate_regions_using_location (*loc);
3131 Editor::separate_regions_using_location (Location& loc)
3133 if (loc.is_mark()) {
3137 AudioRange ar (loc.start(), loc.end(), 1);
3142 separate_regions_between (ts);
3145 /** Separate regions under the selected region */
3147 Editor::separate_under_selected_regions ()
3149 vector<PlaylistState> playlists;
3153 rs = get_regions_from_selection_and_entered();
3155 if (!_session || rs.empty()) {
3159 begin_reversible_command (_("separate region under"));
3161 list<boost::shared_ptr<Region> > regions_to_remove;
3163 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3164 // we can't just remove the region(s) in this loop because
3165 // this removes them from the RegionSelection, and they thus
3166 // disappear from underneath the iterator, and the ++i above
3167 // SEGVs in a puzzling fashion.
3169 // so, first iterate over the regions to be removed from rs and
3170 // add them to the regions_to_remove list, and then
3171 // iterate over the list to actually remove them.
3173 regions_to_remove.push_back ((*i)->region());
3176 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3178 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3181 // is this check necessary?
3185 vector<PlaylistState>::iterator i;
3187 //only take state if this is a new playlist.
3188 for (i = playlists.begin(); i != playlists.end(); ++i) {
3189 if ((*i).playlist == playlist) {
3194 if (i == playlists.end()) {
3196 PlaylistState before;
3197 before.playlist = playlist;
3198 before.before = &playlist->get_state();
3200 playlist->freeze ();
3201 playlists.push_back(before);
3204 //Partition on the region bounds
3205 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3207 //Re-add region that was just removed due to the partition operation
3208 playlist->add_region( (*rl), (*rl)->first_frame() );
3211 vector<PlaylistState>::iterator pl;
3213 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3214 (*pl).playlist->thaw ();
3215 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3218 commit_reversible_command ();
3222 Editor::crop_region_to_selection ()
3224 if (!selection->time.empty()) {
3226 crop_region_to (selection->time.start(), selection->time.end_frame());
3233 if (get_edit_op_range (start, end)) {
3234 crop_region_to (start, end);
3241 Editor::crop_region_to (framepos_t start, framepos_t end)
3243 vector<boost::shared_ptr<Playlist> > playlists;
3244 boost::shared_ptr<Playlist> playlist;
3247 if (selection->tracks.empty()) {
3248 ts = track_views.filter_to_unique_playlists();
3250 ts = selection->tracks.filter_to_unique_playlists ();
3253 sort_track_selection (ts);
3255 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3257 RouteTimeAxisView* rtv;
3259 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3261 boost::shared_ptr<Track> t = rtv->track();
3263 if (t != 0 && ! t->destructive()) {
3265 if ((playlist = rtv->playlist()) != 0) {
3266 playlists.push_back (playlist);
3272 if (playlists.empty()) {
3276 framepos_t the_start;
3279 bool in_command = false;
3281 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3283 boost::shared_ptr<Region> region;
3287 if ((region = (*i)->top_region_at(the_start)) == 0) {
3291 /* now adjust lengths to that we do the right thing
3292 if the selection extends beyond the region
3295 the_start = max (the_start, (framepos_t) region->position());
3296 if (max_framepos - the_start < region->length()) {
3297 the_end = the_start + region->length() - 1;
3299 the_end = max_framepos;
3301 the_end = min (end, the_end);
3302 cnt = the_end - the_start + 1;
3305 begin_reversible_command (_("trim to selection"));
3308 region->clear_changes ();
3309 region->trim_to (the_start, cnt);
3310 _session->add_command (new StatefulDiffCommand (region));
3314 commit_reversible_command ();
3319 Editor::region_fill_track ()
3321 RegionSelection rs = get_regions_from_selection_and_entered ();
3323 if (!_session || rs.empty()) {
3327 framepos_t const end = _session->current_end_frame ();
3328 RegionSelection foo;
3329 bool in_command = false;
3331 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3333 boost::shared_ptr<Region> region ((*i)->region());
3335 boost::shared_ptr<Playlist> pl = region->playlist();
3337 if (end <= region->last_frame()) {
3341 double times = (double) (end - region->last_frame()) / (double) region->length();
3348 begin_reversible_command (Operations::region_fill);
3351 TimeAxisView& tv = (*i)->get_time_axis_view();
3352 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3353 latest_regionviews.clear ();
3354 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3356 pl->clear_changes ();
3357 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3358 _session->add_command (new StatefulDiffCommand (pl));
3362 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3367 selection->set (foo);
3369 commit_reversible_command ();
3374 Editor::region_fill_selection ()
3376 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3380 if (selection->time.empty()) {
3384 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3389 framepos_t start = selection->time[clicked_selection].start;
3390 framepos_t end = selection->time[clicked_selection].end;
3392 boost::shared_ptr<Playlist> playlist;
3394 if (selection->tracks.empty()) {
3398 framepos_t selection_length = end - start;
3399 float times = (float)selection_length / region->length();
3400 bool in_command = false;
3402 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3403 RegionSelection foo;
3405 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3407 if ((playlist = (*i)->playlist()) == 0) {
3412 begin_reversible_command (Operations::fill_selection);
3415 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3416 latest_regionviews.clear ();
3417 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3419 playlist->clear_changes ();
3420 playlist->add_region (RegionFactory::create (region, true), start, times);
3421 _session->add_command (new StatefulDiffCommand (playlist));
3423 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3428 selection->set (foo);
3430 commit_reversible_command ();
3435 Editor::set_region_sync_position ()
3437 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3441 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3443 bool in_command = false;
3445 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3447 if (!(*r)->region()->covers (where)) {
3451 boost::shared_ptr<Region> region ((*r)->region());
3454 begin_reversible_command (_("set sync point"));
3458 region->clear_changes ();
3459 region->set_sync_position (where);
3460 _session->add_command(new StatefulDiffCommand (region));
3464 commit_reversible_command ();
3468 /** Remove the sync positions of the selection */
3470 Editor::remove_region_sync ()
3472 RegionSelection rs = get_regions_from_selection_and_entered ();
3478 begin_reversible_command (_("remove region sync"));
3480 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3482 (*i)->region()->clear_changes ();
3483 (*i)->region()->clear_sync_position ();
3484 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3487 commit_reversible_command ();
3491 Editor::naturalize_region ()
3493 RegionSelection rs = get_regions_from_selection_and_entered ();
3499 if (rs.size() > 1) {
3500 begin_reversible_command (_("move regions to original position"));
3502 begin_reversible_command (_("move region to original position"));
3505 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3506 (*i)->region()->clear_changes ();
3507 (*i)->region()->move_to_natural_position ();
3508 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3511 commit_reversible_command ();
3515 Editor::align_regions (RegionPoint what)
3517 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3523 begin_reversible_command (_("align selection"));
3525 framepos_t const position = get_preferred_edit_position ();
3527 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3528 align_region_internal ((*i)->region(), what, position);
3531 commit_reversible_command ();
3534 struct RegionSortByTime {
3535 bool operator() (const RegionView* a, const RegionView* b) {
3536 return a->region()->position() < b->region()->position();
3541 Editor::align_regions_relative (RegionPoint point)
3543 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3549 framepos_t const position = get_preferred_edit_position ();
3551 framepos_t distance = 0;
3555 list<RegionView*> sorted;
3556 rs.by_position (sorted);
3558 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3563 if (position > r->position()) {
3564 distance = position - r->position();
3566 distance = r->position() - position;
3572 if (position > r->last_frame()) {
3573 distance = position - r->last_frame();
3574 pos = r->position() + distance;
3576 distance = r->last_frame() - position;
3577 pos = r->position() - distance;
3583 pos = r->adjust_to_sync (position);
3584 if (pos > r->position()) {
3585 distance = pos - r->position();
3587 distance = r->position() - pos;
3593 if (pos == r->position()) {
3597 begin_reversible_command (_("align selection (relative)"));
3599 /* move first one specially */
3601 r->clear_changes ();
3602 r->set_position (pos);
3603 _session->add_command(new StatefulDiffCommand (r));
3605 /* move rest by the same amount */
3609 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3611 boost::shared_ptr<Region> region ((*i)->region());
3613 region->clear_changes ();
3616 region->set_position (region->position() + distance);
3618 region->set_position (region->position() - distance);
3621 _session->add_command(new StatefulDiffCommand (region));
3625 commit_reversible_command ();
3629 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3631 begin_reversible_command (_("align region"));
3632 align_region_internal (region, point, position);
3633 commit_reversible_command ();
3637 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3639 region->clear_changes ();
3643 region->set_position (region->adjust_to_sync (position));
3647 if (position > region->length()) {
3648 region->set_position (position - region->length());
3653 region->set_position (position);
3657 _session->add_command(new StatefulDiffCommand (region));
3661 Editor::trim_region_front ()
3667 Editor::trim_region_back ()
3669 trim_region (false);
3673 Editor::trim_region (bool front)
3675 framepos_t where = get_preferred_edit_position();
3676 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3682 begin_reversible_command (front ? _("trim front") : _("trim back"));
3684 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3685 if (!(*i)->region()->locked()) {
3687 (*i)->region()->clear_changes ();
3690 (*i)->region()->trim_front (where);
3691 maybe_locate_with_edit_preroll ( where );
3693 (*i)->region()->trim_end (where);
3694 maybe_locate_with_edit_preroll ( where );
3697 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3701 commit_reversible_command ();
3704 /** Trim the end of the selected regions to the position of the edit cursor */
3706 Editor::trim_region_to_loop ()
3708 Location* loc = _session->locations()->auto_loop_location();
3712 trim_region_to_location (*loc, _("trim to loop"));
3716 Editor::trim_region_to_punch ()
3718 Location* loc = _session->locations()->auto_punch_location();
3722 trim_region_to_location (*loc, _("trim to punch"));
3726 Editor::trim_region_to_location (const Location& loc, const char* str)
3728 RegionSelection rs = get_regions_from_selection_and_entered ();
3729 bool in_command = false;
3731 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3732 RegionView* rv = (*x);
3734 /* require region to span proposed trim */
3735 switch (rv->region()->coverage (loc.start(), loc.end())) {
3736 case Evoral::OverlapInternal:
3742 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3751 if (tav->track() != 0) {
3752 speed = tav->track()->speed();
3755 start = session_frame_to_track_frame (loc.start(), speed);
3756 end = session_frame_to_track_frame (loc.end(), speed);
3758 rv->region()->clear_changes ();
3759 rv->region()->trim_to (start, (end - start));
3762 begin_reversible_command (str);
3765 _session->add_command(new StatefulDiffCommand (rv->region()));
3769 commit_reversible_command ();
3774 Editor::trim_region_to_previous_region_end ()
3776 return trim_to_region(false);
3780 Editor::trim_region_to_next_region_start ()
3782 return trim_to_region(true);
3786 Editor::trim_to_region(bool forward)
3788 RegionSelection rs = get_regions_from_selection_and_entered ();
3789 bool in_command = false;
3791 boost::shared_ptr<Region> next_region;
3793 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3795 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3801 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3809 if (atav->track() != 0) {
3810 speed = atav->track()->speed();
3814 boost::shared_ptr<Region> region = arv->region();
3815 boost::shared_ptr<Playlist> playlist (region->playlist());
3817 region->clear_changes ();
3821 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3827 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3828 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3832 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3838 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3840 arv->region_changed (ARDOUR::bounds_change);
3844 begin_reversible_command (_("trim to region"));
3847 _session->add_command(new StatefulDiffCommand (region));
3851 commit_reversible_command ();
3856 Editor::unfreeze_route ()
3858 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3862 clicked_routeview->track()->unfreeze ();
3866 Editor::_freeze_thread (void* arg)
3868 return static_cast<Editor*>(arg)->freeze_thread ();
3872 Editor::freeze_thread ()
3874 /* create event pool because we may need to talk to the session */
3875 SessionEvent::create_per_thread_pool ("freeze events", 64);
3876 /* create per-thread buffers for process() tree to use */
3877 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3878 current_interthread_info->done = true;
3883 Editor::freeze_route ()
3889 /* stop transport before we start. this is important */
3891 _session->request_transport_speed (0.0);
3893 /* wait for just a little while, because the above call is asynchronous */
3895 Glib::usleep (250000);
3897 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3901 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3903 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3904 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3906 d.set_title (_("Cannot freeze"));
3911 if (clicked_routeview->track()->has_external_redirects()) {
3912 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"
3913 "Freezing will only process the signal as far as the first send/insert/return."),
3914 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3916 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3917 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3918 d.set_title (_("Freeze Limits"));
3920 int response = d.run ();
3923 case Gtk::RESPONSE_CANCEL:
3930 InterThreadInfo itt;
3931 current_interthread_info = &itt;
3933 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3935 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3937 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3939 while (!itt.done && !itt.cancel) {
3940 gtk_main_iteration ();
3943 current_interthread_info = 0;
3947 Editor::bounce_range_selection (bool replace, bool enable_processing)
3949 if (selection->time.empty()) {
3953 TrackSelection views = selection->tracks;
3955 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3957 if (enable_processing) {
3959 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3961 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3963 _("You can't perform this operation because the processing of the signal "
3964 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3965 "You can do this without processing, which is a different operation.")
3967 d.set_title (_("Cannot bounce"));
3974 framepos_t start = selection->time[clicked_selection].start;
3975 framepos_t end = selection->time[clicked_selection].end;
3976 framepos_t cnt = end - start + 1;
3977 bool in_command = false;
3979 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3981 RouteTimeAxisView* rtv;
3983 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3987 boost::shared_ptr<Playlist> playlist;
3989 if ((playlist = rtv->playlist()) == 0) {
3993 InterThreadInfo itt;
3995 playlist->clear_changes ();
3996 playlist->clear_owned_changes ();
3998 boost::shared_ptr<Region> r;
4000 if (enable_processing) {
4001 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4003 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4011 list<AudioRange> ranges;
4012 ranges.push_back (AudioRange (start, start+cnt, 0));
4013 playlist->cut (ranges); // discard result
4014 playlist->add_region (r, start);
4018 begin_reversible_command (_("bounce range"));
4021 vector<Command*> cmds;
4022 playlist->rdiff (cmds);
4023 _session->add_commands (cmds);
4025 _session->add_command (new StatefulDiffCommand (playlist));
4029 commit_reversible_command ();
4033 /** Delete selected regions, automation points or a time range */
4037 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4038 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4039 bool deleted = false;
4040 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4041 deleted = current_mixer_strip->delete_processors ();
4047 /** Cut selected regions, automation points or a time range */
4054 /** Copy selected regions, automation points or a time range */
4062 /** @return true if a Cut, Copy or Clear is possible */
4064 Editor::can_cut_copy () const
4066 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4073 /** Cut, copy or clear selected regions, automation points or a time range.
4074 * @param op Operation (Delete, Cut, Copy or Clear)
4077 Editor::cut_copy (CutCopyOp op)
4079 /* only cancel selection if cut/copy is successful.*/
4085 opname = _("delete");
4094 opname = _("clear");
4098 /* if we're deleting something, and the mouse is still pressed,
4099 the thing we started a drag for will be gone when we release
4100 the mouse button(s). avoid this. see part 2 at the end of
4104 if (op == Delete || op == Cut || op == Clear) {
4105 if (_drags->active ()) {
4110 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4111 cut_buffer->clear ();
4113 if (entered_marker) {
4115 /* cut/delete op while pointing at a marker */
4118 Location* loc = find_location_from_marker (entered_marker, ignored);
4120 if (_session && loc) {
4121 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4128 switch (mouse_mode) {
4131 begin_reversible_command (opname + ' ' + X_("MIDI"));
4133 commit_reversible_command ();
4139 bool did_edit = false;
4141 if (!selection->regions.empty() || !selection->points.empty()) {
4142 begin_reversible_command (opname + ' ' + _("objects"));
4145 if (!selection->regions.empty()) {
4146 cut_copy_regions (op, selection->regions);
4148 if (op == Cut || op == Delete) {
4149 selection->clear_regions ();
4153 if (!selection->points.empty()) {
4154 cut_copy_points (op);
4156 if (op == Cut || op == Delete) {
4157 selection->clear_points ();
4160 } else if (selection->time.empty()) {
4161 framepos_t start, end;
4162 /* no time selection, see if we can get an edit range
4165 if (get_edit_op_range (start, end)) {
4166 selection->set (start, end);
4168 } else if (!selection->time.empty()) {
4169 begin_reversible_command (opname + ' ' + _("range"));
4172 cut_copy_ranges (op);
4174 if (op == Cut || op == Delete) {
4175 selection->clear_time ();
4180 /* reset repeated paste state */
4183 commit_reversible_command ();
4186 if (op == Delete || op == Cut || op == Clear) {
4191 struct AutomationRecord {
4192 AutomationRecord () : state (0) , line(NULL) {}
4193 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4195 XMLNode* state; ///< state before any operation
4196 const AutomationLine* line; ///< line this came from
4197 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4200 /** Cut, copy or clear selected automation points.
4201 * @param op Operation (Cut, Copy or Clear)
4204 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4206 if (selection->points.empty ()) {
4210 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4211 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4213 /* Keep a record of the AutomationLists that we end up using in this operation */
4214 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4217 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4218 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4219 const AutomationLine& line = (*i)->line();
4220 const boost::shared_ptr<AutomationList> al = line.the_list();
4221 if (lists.find (al) == lists.end ()) {
4222 /* We haven't seen this list yet, so make a record for it. This includes
4223 taking a copy of its current state, in case this is needed for undo later.
4225 lists[al] = AutomationRecord (&al->get_state (), &line);
4229 if (op == Cut || op == Copy) {
4230 /* This operation will involve putting things in the cut buffer, so create an empty
4231 ControlList for each of our source lists to put the cut buffer data in.
4233 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4234 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4237 /* Add all selected points to the relevant copy ControlLists */
4238 framepos_t start = std::numeric_limits<framepos_t>::max();
4239 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4240 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4241 AutomationList::const_iterator j = (*i)->model();
4243 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4245 /* Update earliest MIDI start time in beats */
4246 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4248 /* Update earliest session start time in frames */
4249 start = std::min(start, (*i)->line().session_position(j));
4253 /* Snap start time backwards, so copy/paste is snap aligned. */
4255 if (earliest == Evoral::Beats::max()) {
4256 earliest = Evoral::Beats(); // Weird... don't offset
4258 earliest.round_down_to_beat();
4260 if (start == std::numeric_limits<double>::max()) {
4261 start = 0; // Weird... don't offset
4263 snap_to(start, RoundDownMaybe);
4266 const double line_offset = midi ? earliest.to_double() : start;
4267 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4268 /* Correct this copy list so that it is relative to the earliest
4269 start time, so relative ordering between points is preserved
4270 when copying from several lists and the paste starts at the
4271 earliest copied piece of data. */
4272 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4273 (*j)->when -= line_offset;
4276 /* And add it to the cut buffer */
4277 cut_buffer->add (i->second.copy);
4281 if (op == Delete || op == Cut) {
4282 /* This operation needs to remove things from the main AutomationList, so do that now */
4284 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4285 i->first->freeze ();
4288 /* Remove each selected point from its AutomationList */
4289 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4290 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4291 al->erase ((*i)->model ());
4294 /* Thaw the lists and add undo records for them */
4295 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4296 boost::shared_ptr<AutomationList> al = i->first;
4298 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4303 /** Cut, copy or clear selected automation points.
4304 * @param op Operation (Cut, Copy or Clear)
4307 Editor::cut_copy_midi (CutCopyOp op)
4309 Evoral::Beats earliest = Evoral::Beats::max();
4310 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4311 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4313 if (!mrv->selection().empty()) {
4314 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4316 mrv->cut_copy_clear (op);
4318 /* XXX: not ideal, as there may be more than one track involved in the selection */
4319 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4323 if (!selection->points.empty()) {
4324 cut_copy_points (op, earliest, true);
4325 if (op == Cut || op == Delete) {
4326 selection->clear_points ();
4331 struct lt_playlist {
4332 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4333 return a.playlist < b.playlist;
4337 struct PlaylistMapping {
4339 boost::shared_ptr<Playlist> pl;
4341 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4344 /** Remove `clicked_regionview' */
4346 Editor::remove_clicked_region ()
4348 if (clicked_routeview == 0 || clicked_regionview == 0) {
4352 begin_reversible_command (_("remove region"));
4354 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4356 playlist->clear_changes ();
4357 playlist->clear_owned_changes ();
4358 playlist->remove_region (clicked_regionview->region());
4359 if (Config->get_edit_mode() == Ripple)
4360 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4362 /* We might have removed regions, which alters other regions' layering_index,
4363 so we need to do a recursive diff here.
4365 vector<Command*> cmds;
4366 playlist->rdiff (cmds);
4367 _session->add_commands (cmds);
4369 _session->add_command(new StatefulDiffCommand (playlist));
4370 commit_reversible_command ();
4374 /** Remove the selected regions */
4376 Editor::remove_selected_regions ()
4378 RegionSelection rs = get_regions_from_selection_and_entered ();
4380 if (!_session || rs.empty()) {
4384 list<boost::shared_ptr<Region> > regions_to_remove;
4386 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4387 // we can't just remove the region(s) in this loop because
4388 // this removes them from the RegionSelection, and they thus
4389 // disappear from underneath the iterator, and the ++i above
4390 // SEGVs in a puzzling fashion.
4392 // so, first iterate over the regions to be removed from rs and
4393 // add them to the regions_to_remove list, and then
4394 // iterate over the list to actually remove them.
4396 regions_to_remove.push_back ((*i)->region());
4399 vector<boost::shared_ptr<Playlist> > playlists;
4401 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4403 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4406 // is this check necessary?
4410 /* get_regions_from_selection_and_entered() guarantees that
4411 the playlists involved are unique, so there is no need
4415 playlists.push_back (playlist);
4417 playlist->clear_changes ();
4418 playlist->clear_owned_changes ();
4419 playlist->freeze ();
4420 playlist->remove_region (*rl);
4421 if (Config->get_edit_mode() == Ripple)
4422 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4426 vector<boost::shared_ptr<Playlist> >::iterator pl;
4427 bool in_command = false;
4429 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4432 /* We might have removed regions, which alters other regions' layering_index,
4433 so we need to do a recursive diff here.
4437 begin_reversible_command (_("remove region"));
4440 vector<Command*> cmds;
4441 (*pl)->rdiff (cmds);
4442 _session->add_commands (cmds);
4444 _session->add_command(new StatefulDiffCommand (*pl));
4448 commit_reversible_command ();
4452 /** Cut, copy or clear selected regions.
4453 * @param op Operation (Cut, Copy or Clear)
4456 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4458 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4459 a map when we want ordered access to both elements. i think.
4462 vector<PlaylistMapping> pmap;
4464 framepos_t first_position = max_framepos;
4466 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4467 FreezeList freezelist;
4469 /* get ordering correct before we cut/copy */
4471 rs.sort_by_position_and_track ();
4473 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4475 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4477 if (op == Cut || op == Clear || op == Delete) {
4478 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4481 FreezeList::iterator fl;
4483 // only take state if this is a new playlist.
4484 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4490 if (fl == freezelist.end()) {
4491 pl->clear_changes();
4492 pl->clear_owned_changes ();
4494 freezelist.insert (pl);
4499 TimeAxisView* tv = &(*x)->get_time_axis_view();
4500 vector<PlaylistMapping>::iterator z;
4502 for (z = pmap.begin(); z != pmap.end(); ++z) {
4503 if ((*z).tv == tv) {
4508 if (z == pmap.end()) {
4509 pmap.push_back (PlaylistMapping (tv));
4513 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4515 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4518 /* region not yet associated with a playlist (e.g. unfinished
4525 TimeAxisView& tv = (*x)->get_time_axis_view();
4526 boost::shared_ptr<Playlist> npl;
4527 RegionSelection::iterator tmp;
4534 vector<PlaylistMapping>::iterator z;
4536 for (z = pmap.begin(); z != pmap.end(); ++z) {
4537 if ((*z).tv == &tv) {
4542 assert (z != pmap.end());
4545 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4553 boost::shared_ptr<Region> r = (*x)->region();
4554 boost::shared_ptr<Region> _xx;
4560 pl->remove_region (r);
4561 if (Config->get_edit_mode() == Ripple)
4562 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4566 _xx = RegionFactory::create (r);
4567 npl->add_region (_xx, r->position() - first_position);
4568 pl->remove_region (r);
4569 if (Config->get_edit_mode() == Ripple)
4570 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4574 /* copy region before adding, so we're not putting same object into two different playlists */
4575 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4579 pl->remove_region (r);
4580 if (Config->get_edit_mode() == Ripple)
4581 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4590 list<boost::shared_ptr<Playlist> > foo;
4592 /* the pmap is in the same order as the tracks in which selected regions occured */
4594 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4597 foo.push_back ((*i).pl);
4602 cut_buffer->set (foo);
4606 _last_cut_copy_source_track = 0;
4608 _last_cut_copy_source_track = pmap.front().tv;
4612 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4615 /* We might have removed regions, which alters other regions' layering_index,
4616 so we need to do a recursive diff here.
4618 vector<Command*> cmds;
4619 (*pl)->rdiff (cmds);
4620 _session->add_commands (cmds);
4622 _session->add_command (new StatefulDiffCommand (*pl));
4627 Editor::cut_copy_ranges (CutCopyOp op)
4629 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4631 /* Sort the track selection now, so that it if is used, the playlists
4632 selected by the calls below to cut_copy_clear are in the order that
4633 their tracks appear in the editor. This makes things like paste
4634 of ranges work properly.
4637 sort_track_selection (ts);
4640 if (!entered_track) {
4643 ts.push_back (entered_track);
4646 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4647 (*i)->cut_copy_clear (*selection, op);
4652 Editor::paste (float times, bool from_context)
4654 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4656 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4660 Editor::mouse_paste ()
4665 if (!mouse_frame (where, ignored)) {
4670 paste_internal (where, 1);
4674 Editor::paste_internal (framepos_t position, float times)
4676 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4678 if (cut_buffer->empty(internal_editing())) {
4682 if (position == max_framepos) {
4683 position = get_preferred_edit_position();
4684 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4687 if (position == last_paste_pos) {
4688 /* repeated paste in the same position */
4691 /* paste in new location, reset repeated paste state */
4693 last_paste_pos = position;
4696 /* get everything in the correct order */
4699 if (!selection->tracks.empty()) {
4700 /* If there is a track selection, paste into exactly those tracks and
4701 only those tracks. This allows the user to be explicit and override
4702 the below "do the reasonable thing" logic. */
4703 ts = selection->tracks.filter_to_unique_playlists ();
4704 sort_track_selection (ts);
4706 /* Figure out which track to base the paste at. */
4707 TimeAxisView* base_track = NULL;
4708 if (_edit_point == Editing::EditAtMouse && entered_track) {
4709 /* With the mouse edit point, paste onto the track under the mouse. */
4710 base_track = entered_track;
4711 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4712 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4713 base_track = &entered_regionview->get_time_axis_view();
4714 } else if (_last_cut_copy_source_track) {
4715 /* Paste to the track that the cut/copy came from (see mantis #333). */
4716 base_track = _last_cut_copy_source_track;
4718 /* This is "impossible" since we've copied... well, do nothing. */
4722 /* Walk up to parent if necessary, so base track is a route. */
4723 while (base_track->get_parent()) {
4724 base_track = base_track->get_parent();
4727 /* Add base track and all tracks below it. The paste logic will select
4728 the appropriate object types from the cut buffer in relative order. */
4729 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4730 if ((*i)->order() >= base_track->order()) {
4735 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4736 sort_track_selection (ts);
4738 /* Add automation children of each track in order, for pasting several lines. */
4739 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4740 /* Add any automation children for pasting several lines */
4741 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4746 typedef RouteTimeAxisView::AutomationTracks ATracks;
4747 const ATracks& atracks = rtv->automation_tracks();
4748 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4749 i = ts.insert(i, a->second.get());
4754 /* We now have a list of trackviews starting at base_track, including
4755 automation children, in the order shown in the editor, e.g. R1,
4756 R1.A1, R1.A2, R2, R2.A1, ... */
4759 begin_reversible_command (Operations::paste);
4761 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4762 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4763 /* Only one line copied, and one automation track selected. Do a
4764 "greedy" paste from one automation type to another. */
4766 PasteContext ctx(paste_count, times, ItemCounts(), true);
4767 ts.front()->paste (position, *cut_buffer, ctx);
4771 /* Paste into tracks */
4773 PasteContext ctx(paste_count, times, ItemCounts(), false);
4774 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4775 (*i)->paste (position, *cut_buffer, ctx);
4779 commit_reversible_command ();
4783 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4785 if (regions.empty ()) {
4789 boost::shared_ptr<Playlist> playlist;
4790 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4791 RegionSelection foo;
4793 framepos_t const start_frame = regions.start ();
4794 framepos_t const end_frame = regions.end_frame ();
4796 begin_reversible_command (Operations::duplicate_region);
4798 selection->clear_regions ();
4800 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4802 boost::shared_ptr<Region> r ((*i)->region());
4804 TimeAxisView& tv = (*i)->get_time_axis_view();
4805 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4806 latest_regionviews.clear ();
4807 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4809 playlist = (*i)->region()->playlist();
4810 playlist->clear_changes ();
4811 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4812 _session->add_command(new StatefulDiffCommand (playlist));
4816 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4820 selection->set (foo);
4823 commit_reversible_command ();
4827 Editor::duplicate_selection (float times)
4829 if (selection->time.empty() || selection->tracks.empty()) {
4833 boost::shared_ptr<Playlist> playlist;
4834 vector<boost::shared_ptr<Region> > new_regions;
4835 vector<boost::shared_ptr<Region> >::iterator ri;
4837 create_region_from_selection (new_regions);
4839 if (new_regions.empty()) {
4843 ri = new_regions.begin();
4845 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4846 bool in_command = false;
4848 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4849 if ((playlist = (*i)->playlist()) == 0) {
4852 playlist->clear_changes ();
4854 if (clicked_selection) {
4855 end = selection->time[clicked_selection].end;
4857 end = selection->time.end_frame();
4859 playlist->duplicate (*ri, end, times);
4862 begin_reversible_command (_("duplicate selection"));
4865 _session->add_command (new StatefulDiffCommand (playlist));
4868 if (ri == new_regions.end()) {
4874 commit_reversible_command ();
4878 /** Reset all selected points to the relevant default value */
4880 Editor::reset_point_selection ()
4882 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4883 ARDOUR::AutomationList::iterator j = (*i)->model ();
4884 (*j)->value = (*i)->line().the_list()->default_value ();
4889 Editor::center_playhead ()
4891 float const page = _visible_canvas_width * samples_per_pixel;
4892 center_screen_internal (playhead_cursor->current_frame (), page);
4896 Editor::center_edit_point ()
4898 float const page = _visible_canvas_width * samples_per_pixel;
4899 center_screen_internal (get_preferred_edit_position(), page);
4902 /** Caller must begin and commit a reversible command */
4904 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4906 playlist->clear_changes ();
4908 _session->add_command (new StatefulDiffCommand (playlist));
4912 Editor::nudge_track (bool use_edit, bool forwards)
4914 boost::shared_ptr<Playlist> playlist;
4915 framepos_t distance;
4916 framepos_t next_distance;
4920 start = get_preferred_edit_position();
4925 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4929 if (selection->tracks.empty()) {
4933 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4934 bool in_command = false;
4936 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4938 if ((playlist = (*i)->playlist()) == 0) {
4942 playlist->clear_changes ();
4943 playlist->clear_owned_changes ();
4945 playlist->nudge_after (start, distance, forwards);
4948 begin_reversible_command (_("nudge track"));
4951 vector<Command*> cmds;
4953 playlist->rdiff (cmds);
4954 _session->add_commands (cmds);
4956 _session->add_command (new StatefulDiffCommand (playlist));
4960 commit_reversible_command ();
4965 Editor::remove_last_capture ()
4967 vector<string> choices;
4974 if (Config->get_verify_remove_last_capture()) {
4975 prompt = _("Do you really want to destroy the last capture?"
4976 "\n(This is destructive and cannot be undone)");
4978 choices.push_back (_("No, do nothing."));
4979 choices.push_back (_("Yes, destroy it."));
4981 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4983 if (prompter.run () == 1) {
4984 _session->remove_last_capture ();
4985 _regions->redisplay ();
4989 _session->remove_last_capture();
4990 _regions->redisplay ();
4995 Editor::normalize_region ()
5001 RegionSelection rs = get_regions_from_selection_and_entered ();
5007 NormalizeDialog dialog (rs.size() > 1);
5009 if (dialog.run () == RESPONSE_CANCEL) {
5013 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5016 /* XXX: should really only count audio regions here */
5017 int const regions = rs.size ();
5019 /* Make a list of the selected audio regions' maximum amplitudes, and also
5020 obtain the maximum amplitude of them all.
5022 list<double> max_amps;
5024 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5025 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5027 dialog.descend (1.0 / regions);
5028 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5031 /* the user cancelled the operation */
5035 max_amps.push_back (a);
5036 max_amp = max (max_amp, a);
5041 list<double>::const_iterator a = max_amps.begin ();
5042 bool in_command = false;
5044 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5045 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5050 arv->region()->clear_changes ();
5052 double const amp = dialog.normalize_individually() ? *a : max_amp;
5054 arv->audio_region()->normalize (amp, dialog.target ());
5057 begin_reversible_command (_("normalize"));
5060 _session->add_command (new StatefulDiffCommand (arv->region()));
5066 commit_reversible_command ();
5072 Editor::reset_region_scale_amplitude ()
5078 RegionSelection rs = get_regions_from_selection_and_entered ();
5084 bool in_command = false;
5086 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5087 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5090 arv->region()->clear_changes ();
5091 arv->audio_region()->set_scale_amplitude (1.0f);
5094 begin_reversible_command ("reset gain");
5097 _session->add_command (new StatefulDiffCommand (arv->region()));
5101 commit_reversible_command ();
5106 Editor::adjust_region_gain (bool up)
5108 RegionSelection rs = get_regions_from_selection_and_entered ();
5110 if (!_session || rs.empty()) {
5114 bool in_command = false;
5116 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5117 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5122 arv->region()->clear_changes ();
5124 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5132 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5135 begin_reversible_command ("adjust region gain");
5138 _session->add_command (new StatefulDiffCommand (arv->region()));
5142 commit_reversible_command ();
5148 Editor::reverse_region ()
5154 Reverse rev (*_session);
5155 apply_filter (rev, _("reverse regions"));
5159 Editor::strip_region_silence ()
5165 RegionSelection rs = get_regions_from_selection_and_entered ();
5171 std::list<RegionView*> audio_only;
5173 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5174 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5176 audio_only.push_back (arv);
5180 StripSilenceDialog d (_session, audio_only);
5181 int const r = d.run ();
5185 if (r == Gtk::RESPONSE_OK) {
5186 ARDOUR::AudioIntervalMap silences;
5187 d.silences (silences);
5188 StripSilence s (*_session, silences, d.fade_length());
5189 apply_filter (s, _("strip silence"), &d);
5194 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5196 Evoral::Sequence<Evoral::Beats>::Notes selected;
5197 mrv.selection_as_notelist (selected, true);
5199 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5200 v.push_back (selected);
5202 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5203 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5205 return op (mrv.midi_region()->model(), pos_beats, v);
5209 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5215 bool in_command = false;
5217 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5218 RegionSelection::const_iterator tmp = r;
5221 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5224 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5227 begin_reversible_command (op.name ());
5231 _session->add_command (cmd);
5239 commit_reversible_command ();
5244 Editor::fork_region ()
5246 RegionSelection rs = get_regions_from_selection_and_entered ();
5252 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5253 bool in_command = false;
5257 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5258 RegionSelection::iterator tmp = r;
5261 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5265 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5266 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5267 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5270 begin_reversible_command (_("Fork Region(s)"));
5273 playlist->clear_changes ();
5274 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5275 _session->add_command(new StatefulDiffCommand (playlist));
5277 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5285 commit_reversible_command ();
5290 Editor::quantize_region ()
5293 quantize_regions(get_regions_from_selection_and_entered ());
5298 Editor::quantize_regions (const RegionSelection& rs)
5300 if (rs.n_midi_regions() == 0) {
5304 if (!quantize_dialog) {
5305 quantize_dialog = new QuantizeDialog (*this);
5308 quantize_dialog->present ();
5309 const int r = quantize_dialog->run ();
5310 quantize_dialog->hide ();
5312 if (r == Gtk::RESPONSE_OK) {
5313 Quantize quant (quantize_dialog->snap_start(),
5314 quantize_dialog->snap_end(),
5315 quantize_dialog->start_grid_size(),
5316 quantize_dialog->end_grid_size(),
5317 quantize_dialog->strength(),
5318 quantize_dialog->swing(),
5319 quantize_dialog->threshold());
5321 apply_midi_note_edit_op (quant, rs);
5326 Editor::legatize_region (bool shrink_only)
5329 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5334 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5336 if (rs.n_midi_regions() == 0) {
5340 Legatize legatize(shrink_only);
5341 apply_midi_note_edit_op (legatize, rs);
5345 Editor::transform_region ()
5348 transform_regions(get_regions_from_selection_and_entered ());
5353 Editor::transform_regions (const RegionSelection& rs)
5355 if (rs.n_midi_regions() == 0) {
5359 TransformDialog* td = new TransformDialog();
5362 const int r = td->run();
5365 if (r == Gtk::RESPONSE_OK) {
5366 Transform transform(td->get());
5367 apply_midi_note_edit_op(transform, rs);
5372 Editor::insert_patch_change (bool from_context)
5374 RegionSelection rs = get_regions_from_selection_and_entered ();
5380 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5382 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5383 there may be more than one, but the PatchChangeDialog can only offer
5384 one set of patch menus.
5386 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5388 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5389 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5391 if (d.run() == RESPONSE_CANCEL) {
5395 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5396 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5398 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5399 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5406 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5408 RegionSelection rs = get_regions_from_selection_and_entered ();
5414 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5415 bool in_command = false;
5420 int const N = rs.size ();
5422 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5423 RegionSelection::iterator tmp = r;
5426 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5428 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5431 progress->descend (1.0 / N);
5434 if (arv->audio_region()->apply (filter, progress) == 0) {
5436 playlist->clear_changes ();
5437 playlist->clear_owned_changes ();
5439 if (filter.results.empty ()) {
5441 /* no regions returned; remove the old one */
5442 playlist->remove_region (arv->region ());
5446 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5448 /* first region replaces the old one */
5449 playlist->replace_region (arv->region(), *res, (*res)->position());
5453 while (res != filter.results.end()) {
5454 playlist->add_region (*res, (*res)->position());
5459 /* We might have removed regions, which alters other regions' layering_index,
5460 so we need to do a recursive diff here.
5464 begin_reversible_command (command);
5467 vector<Command*> cmds;
5468 playlist->rdiff (cmds);
5469 _session->add_commands (cmds);
5471 _session->add_command(new StatefulDiffCommand (playlist));
5478 progress->ascend ();
5487 commit_reversible_command ();
5492 Editor::external_edit_region ()
5498 Editor::reset_region_gain_envelopes ()
5500 RegionSelection rs = get_regions_from_selection_and_entered ();
5502 if (!_session || rs.empty()) {
5506 bool in_command = false;
5508 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5509 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5511 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5512 XMLNode& before (alist->get_state());
5514 arv->audio_region()->set_default_envelope ();
5517 begin_reversible_command (_("reset region gain"));
5520 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5525 commit_reversible_command ();
5530 Editor::set_region_gain_visibility (RegionView* rv)
5532 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5534 arv->update_envelope_visibility();
5539 Editor::set_gain_envelope_visibility ()
5545 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5546 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5548 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5554 Editor::toggle_gain_envelope_active ()
5556 if (_ignore_region_action) {
5560 RegionSelection rs = get_regions_from_selection_and_entered ();
5562 if (!_session || rs.empty()) {
5566 bool in_command = false;
5568 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5569 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5571 arv->region()->clear_changes ();
5572 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5575 begin_reversible_command (_("region gain envelope active"));
5578 _session->add_command (new StatefulDiffCommand (arv->region()));
5583 commit_reversible_command ();
5588 Editor::toggle_region_lock ()
5590 if (_ignore_region_action) {
5594 RegionSelection rs = get_regions_from_selection_and_entered ();
5596 if (!_session || rs.empty()) {
5600 begin_reversible_command (_("toggle region lock"));
5602 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5603 (*i)->region()->clear_changes ();
5604 (*i)->region()->set_locked (!(*i)->region()->locked());
5605 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5608 commit_reversible_command ();
5612 Editor::toggle_region_video_lock ()
5614 if (_ignore_region_action) {
5618 RegionSelection rs = get_regions_from_selection_and_entered ();
5620 if (!_session || rs.empty()) {
5624 begin_reversible_command (_("Toggle Video Lock"));
5626 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5627 (*i)->region()->clear_changes ();
5628 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5629 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5632 commit_reversible_command ();
5636 Editor::toggle_region_lock_style ()
5638 if (_ignore_region_action) {
5642 RegionSelection rs = get_regions_from_selection_and_entered ();
5644 if (!_session || rs.empty()) {
5648 begin_reversible_command (_("region lock style"));
5650 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5651 (*i)->region()->clear_changes ();
5652 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5653 (*i)->region()->set_position_lock_style (ns);
5654 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5657 commit_reversible_command ();
5661 Editor::toggle_opaque_region ()
5663 if (_ignore_region_action) {
5667 RegionSelection rs = get_regions_from_selection_and_entered ();
5669 if (!_session || rs.empty()) {
5673 begin_reversible_command (_("change region opacity"));
5675 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5676 (*i)->region()->clear_changes ();
5677 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5678 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5681 commit_reversible_command ();
5685 Editor::toggle_record_enable ()
5687 bool new_state = false;
5689 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5690 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5693 if (!rtav->is_track())
5697 new_state = !rtav->track()->record_enabled();
5701 rtav->track()->set_record_enabled (new_state, this);
5706 Editor::toggle_solo ()
5708 bool new_state = false;
5710 boost::shared_ptr<RouteList> rl (new RouteList);
5712 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5713 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5720 new_state = !rtav->route()->soloed ();
5724 rl->push_back (rtav->route());
5727 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5731 Editor::toggle_mute ()
5733 bool new_state = false;
5735 boost::shared_ptr<RouteList> rl (new RouteList);
5737 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5738 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5745 new_state = !rtav->route()->muted();
5749 rl->push_back (rtav->route());
5752 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5756 Editor::toggle_solo_isolate ()
5762 Editor::fade_range ()
5764 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5766 begin_reversible_command (_("fade range"));
5768 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5769 (*i)->fade_range (selection->time);
5772 commit_reversible_command ();
5777 Editor::set_fade_length (bool in)
5779 RegionSelection rs = get_regions_from_selection_and_entered ();
5785 /* we need a region to measure the offset from the start */
5787 RegionView* rv = rs.front ();
5789 framepos_t pos = get_preferred_edit_position();
5793 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5794 /* edit point is outside the relevant region */
5799 if (pos <= rv->region()->position()) {
5803 len = pos - rv->region()->position();
5804 cmd = _("set fade in length");
5806 if (pos >= rv->region()->last_frame()) {
5810 len = rv->region()->last_frame() - pos;
5811 cmd = _("set fade out length");
5814 bool in_command = false;
5816 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5817 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5823 boost::shared_ptr<AutomationList> alist;
5825 alist = tmp->audio_region()->fade_in();
5827 alist = tmp->audio_region()->fade_out();
5830 XMLNode &before = alist->get_state();
5833 tmp->audio_region()->set_fade_in_length (len);
5834 tmp->audio_region()->set_fade_in_active (true);
5836 tmp->audio_region()->set_fade_out_length (len);
5837 tmp->audio_region()->set_fade_out_active (true);
5841 begin_reversible_command (cmd);
5844 XMLNode &after = alist->get_state();
5845 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5849 commit_reversible_command ();
5854 Editor::set_fade_in_shape (FadeShape shape)
5856 RegionSelection rs = get_regions_from_selection_and_entered ();
5861 bool in_command = false;
5863 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5864 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5870 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5871 XMLNode &before = alist->get_state();
5873 tmp->audio_region()->set_fade_in_shape (shape);
5876 begin_reversible_command (_("set fade in shape"));
5879 XMLNode &after = alist->get_state();
5880 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5884 commit_reversible_command ();
5889 Editor::set_fade_out_shape (FadeShape shape)
5891 RegionSelection rs = get_regions_from_selection_and_entered ();
5896 bool in_command = false;
5898 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5899 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5905 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5906 XMLNode &before = alist->get_state();
5908 tmp->audio_region()->set_fade_out_shape (shape);
5911 begin_reversible_command (_("set fade out shape"));
5914 XMLNode &after = alist->get_state();
5915 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5919 commit_reversible_command ();
5924 Editor::set_fade_in_active (bool yn)
5926 RegionSelection rs = get_regions_from_selection_and_entered ();
5931 bool in_command = false;
5933 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5934 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5941 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5943 ar->clear_changes ();
5944 ar->set_fade_in_active (yn);
5947 begin_reversible_command (_("set fade in active"));
5950 _session->add_command (new StatefulDiffCommand (ar));
5954 commit_reversible_command ();
5959 Editor::set_fade_out_active (bool yn)
5961 RegionSelection rs = get_regions_from_selection_and_entered ();
5966 bool in_command = false;
5968 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5969 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5975 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5977 ar->clear_changes ();
5978 ar->set_fade_out_active (yn);
5981 begin_reversible_command (_("set fade out active"));
5984 _session->add_command(new StatefulDiffCommand (ar));
5988 commit_reversible_command ();
5993 Editor::toggle_region_fades (int dir)
5995 if (_ignore_region_action) {
5999 boost::shared_ptr<AudioRegion> ar;
6002 RegionSelection rs = get_regions_from_selection_and_entered ();
6008 RegionSelection::iterator i;
6009 for (i = rs.begin(); i != rs.end(); ++i) {
6010 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6012 yn = ar->fade_out_active ();
6014 yn = ar->fade_in_active ();
6020 if (i == rs.end()) {
6024 /* XXX should this undo-able? */
6025 bool in_command = false;
6027 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6028 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6031 ar->clear_changes ();
6033 if (dir == 1 || dir == 0) {
6034 ar->set_fade_in_active (!yn);
6037 if (dir == -1 || dir == 0) {
6038 ar->set_fade_out_active (!yn);
6041 begin_reversible_command (_("toggle fade active"));
6044 _session->add_command(new StatefulDiffCommand (ar));
6048 commit_reversible_command ();
6053 /** Update region fade visibility after its configuration has been changed */
6055 Editor::update_region_fade_visibility ()
6057 bool _fade_visibility = _session->config.get_show_region_fades ();
6059 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6060 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6062 if (_fade_visibility) {
6063 v->audio_view()->show_all_fades ();
6065 v->audio_view()->hide_all_fades ();
6072 Editor::set_edit_point ()
6077 if (!mouse_frame (where, ignored)) {
6083 if (selection->markers.empty()) {
6085 mouse_add_new_marker (where);
6090 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6093 loc->move_to (where);
6099 Editor::set_playhead_cursor ()
6101 if (entered_marker) {
6102 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6107 if (!mouse_frame (where, ignored)) {
6114 _session->request_locate (where, _session->transport_rolling());
6118 if (ARDOUR_UI::config()->get_follow_edits()) {
6119 cancel_time_selection();
6124 Editor::split_region ()
6126 //if a range is selected, separate it
6127 if ( !selection->time.empty()) {
6128 separate_regions_between (selection->time);
6132 //if no range was selected, try to find some regions to split
6133 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6135 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6137 framepos_t where = get_preferred_edit_position ();
6143 split_regions_at (where, rs);
6147 struct EditorOrderRouteSorter {
6148 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6149 return a->order_key () < b->order_key ();
6154 Editor::select_next_route()
6156 if (selection->tracks.empty()) {
6157 selection->set (track_views.front());
6161 TimeAxisView* current = selection->tracks.front();
6165 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6166 if (*i == current) {
6168 if (i != track_views.end()) {
6171 current = (*(track_views.begin()));
6172 //selection->set (*(track_views.begin()));
6177 rui = dynamic_cast<RouteUI *>(current);
6178 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6180 selection->set(current);
6182 ensure_time_axis_view_is_visible (*current, false);
6186 Editor::select_prev_route()
6188 if (selection->tracks.empty()) {
6189 selection->set (track_views.front());
6193 TimeAxisView* current = selection->tracks.front();
6197 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6198 if (*i == current) {
6200 if (i != track_views.rend()) {
6203 current = *(track_views.rbegin());
6208 rui = dynamic_cast<RouteUI *>(current);
6209 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6211 selection->set (current);
6213 ensure_time_axis_view_is_visible (*current, false);
6217 Editor::set_loop_from_selection (bool play)
6219 if (_session == 0) {
6223 framepos_t start, end;
6224 if (!get_selection_extents ( start, end))
6227 set_loop_range (start, end, _("set loop range from selection"));
6230 _session->request_play_loop (true, true);
6235 Editor::set_loop_from_region (bool play)
6237 framepos_t start, end;
6238 if (!get_selection_extents ( start, end))
6241 set_loop_range (start, end, _("set loop range from region"));
6244 _session->request_locate (start, true);
6245 _session->request_play_loop (true);
6250 Editor::set_punch_from_selection ()
6252 if (_session == 0) {
6256 framepos_t start, end;
6257 if (!get_selection_extents ( start, end))
6260 set_punch_range (start, end, _("set punch range from selection"));
6264 Editor::set_session_extents_from_selection ()
6266 if (_session == 0) {
6270 framepos_t start, end;
6271 if (!get_selection_extents ( start, end))
6275 if ((loc = _session->locations()->session_range_location()) == 0) {
6276 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6278 XMLNode &before = loc->get_state();
6280 _session->set_session_extents ( start, end );
6282 XMLNode &after = loc->get_state();
6284 begin_reversible_command (_("set session start/end from selection"));
6286 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6288 commit_reversible_command ();
6293 Editor::set_punch_start_from_edit_point ()
6297 framepos_t start = 0;
6298 framepos_t end = max_framepos;
6300 //use the existing punch end, if any
6301 Location* tpl = transport_punch_location();
6306 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6307 start = _session->audible_frame();
6309 start = get_preferred_edit_position();
6312 //snap the selection start/end
6315 //if there's not already a sensible selection endpoint, go "forever"
6316 if ( start > end ) {
6320 set_punch_range (start, end, _("set punch start from EP"));
6326 Editor::set_punch_end_from_edit_point ()
6330 framepos_t start = 0;
6331 framepos_t end = max_framepos;
6333 //use the existing punch start, if any
6334 Location* tpl = transport_punch_location();
6336 start = tpl->start();
6339 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6340 end = _session->audible_frame();
6342 end = get_preferred_edit_position();
6345 //snap the selection start/end
6348 set_punch_range (start, end, _("set punch end from EP"));
6354 Editor::set_loop_start_from_edit_point ()
6358 framepos_t start = 0;
6359 framepos_t end = max_framepos;
6361 //use the existing loop end, if any
6362 Location* tpl = transport_loop_location();
6367 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6368 start = _session->audible_frame();
6370 start = get_preferred_edit_position();
6373 //snap the selection start/end
6376 //if there's not already a sensible selection endpoint, go "forever"
6377 if ( start > end ) {
6381 set_loop_range (start, end, _("set loop start from EP"));
6387 Editor::set_loop_end_from_edit_point ()
6391 framepos_t start = 0;
6392 framepos_t end = max_framepos;
6394 //use the existing loop start, if any
6395 Location* tpl = transport_loop_location();
6397 start = tpl->start();
6400 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6401 end = _session->audible_frame();
6403 end = get_preferred_edit_position();
6406 //snap the selection start/end
6409 set_loop_range (start, end, _("set loop end from EP"));
6414 Editor::set_punch_from_region ()
6416 framepos_t start, end;
6417 if (!get_selection_extents ( start, end))
6420 set_punch_range (start, end, _("set punch range from region"));
6424 Editor::pitch_shift_region ()
6426 RegionSelection rs = get_regions_from_selection_and_entered ();
6428 RegionSelection audio_rs;
6429 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6430 if (dynamic_cast<AudioRegionView*> (*i)) {
6431 audio_rs.push_back (*i);
6435 if (audio_rs.empty()) {
6439 pitch_shift (audio_rs, 1.2);
6443 Editor::transpose_region ()
6445 RegionSelection rs = get_regions_from_selection_and_entered ();
6447 list<MidiRegionView*> midi_region_views;
6448 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6449 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6451 midi_region_views.push_back (mrv);
6456 int const r = d.run ();
6457 if (r != RESPONSE_ACCEPT) {
6461 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6462 (*i)->midi_region()->transpose (d.semitones ());
6467 Editor::set_tempo_from_region ()
6469 RegionSelection rs = get_regions_from_selection_and_entered ();
6471 if (!_session || rs.empty()) {
6475 RegionView* rv = rs.front();
6477 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6481 Editor::use_range_as_bar ()
6483 framepos_t start, end;
6484 if (get_edit_op_range (start, end)) {
6485 define_one_bar (start, end);
6490 Editor::define_one_bar (framepos_t start, framepos_t end)
6492 framepos_t length = end - start;
6494 const Meter& m (_session->tempo_map().meter_at (start));
6496 /* length = 1 bar */
6498 /* now we want frames per beat.
6499 we have frames per bar, and beats per bar, so ...
6502 /* XXXX METER MATH */
6504 double frames_per_beat = length / m.divisions_per_bar();
6506 /* beats per minute = */
6508 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6510 /* now decide whether to:
6512 (a) set global tempo
6513 (b) add a new tempo marker
6517 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6519 bool do_global = false;
6521 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6523 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6524 at the start, or create a new marker
6527 vector<string> options;
6528 options.push_back (_("Cancel"));
6529 options.push_back (_("Add new marker"));
6530 options.push_back (_("Set global tempo"));
6533 _("Define one bar"),
6534 _("Do you want to set the global tempo or add a new tempo marker?"),
6538 c.set_default_response (2);
6554 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6555 if the marker is at the region starter, change it, otherwise add
6560 begin_reversible_command (_("set tempo from region"));
6561 XMLNode& before (_session->tempo_map().get_state());
6564 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6565 } else if (t.frame() == start) {
6566 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6568 Timecode::BBT_Time bbt;
6569 _session->tempo_map().bbt_time (start, bbt);
6570 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6573 XMLNode& after (_session->tempo_map().get_state());
6575 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6576 commit_reversible_command ();
6580 Editor::split_region_at_transients ()
6582 AnalysisFeatureList positions;
6584 RegionSelection rs = get_regions_from_selection_and_entered ();
6586 if (!_session || rs.empty()) {
6590 begin_reversible_command (_("split regions"));
6592 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6594 RegionSelection::iterator tmp;
6599 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6601 if (ar && (ar->get_transients (positions) == 0)) {
6602 split_region_at_points ((*i)->region(), positions, true);
6609 commit_reversible_command ();
6614 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6616 bool use_rhythmic_rodent = false;
6618 boost::shared_ptr<Playlist> pl = r->playlist();
6620 list<boost::shared_ptr<Region> > new_regions;
6626 if (positions.empty()) {
6631 if (positions.size() > 20 && can_ferret) {
6632 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);
6633 MessageDialog msg (msgstr,
6636 Gtk::BUTTONS_OK_CANCEL);
6639 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6640 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6642 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6645 msg.set_title (_("Excessive split?"));
6648 int response = msg.run();
6654 case RESPONSE_APPLY:
6655 use_rhythmic_rodent = true;
6662 if (use_rhythmic_rodent) {
6663 show_rhythm_ferret ();
6667 AnalysisFeatureList::const_iterator x;
6669 pl->clear_changes ();
6670 pl->clear_owned_changes ();
6672 x = positions.begin();
6674 if (x == positions.end()) {
6679 pl->remove_region (r);
6683 while (x != positions.end()) {
6685 /* deal with positons that are out of scope of present region bounds */
6686 if (*x <= 0 || *x > r->length()) {
6691 /* file start = original start + how far we from the initial position ?
6694 framepos_t file_start = r->start() + pos;
6696 /* length = next position - current position
6699 framepos_t len = (*x) - pos;
6701 /* XXX we do we really want to allow even single-sample regions?
6702 shouldn't we have some kind of lower limit on region size?
6711 if (RegionFactory::region_name (new_name, r->name())) {
6715 /* do NOT announce new regions 1 by one, just wait till they are all done */
6719 plist.add (ARDOUR::Properties::start, file_start);
6720 plist.add (ARDOUR::Properties::length, len);
6721 plist.add (ARDOUR::Properties::name, new_name);
6722 plist.add (ARDOUR::Properties::layer, 0);
6724 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6725 /* because we set annouce to false, manually add the new region to the
6728 RegionFactory::map_add (nr);
6730 pl->add_region (nr, r->position() + pos);
6733 new_regions.push_front(nr);
6742 RegionFactory::region_name (new_name, r->name());
6744 /* Add the final region */
6747 plist.add (ARDOUR::Properties::start, r->start() + pos);
6748 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6749 plist.add (ARDOUR::Properties::name, new_name);
6750 plist.add (ARDOUR::Properties::layer, 0);
6752 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6753 /* because we set annouce to false, manually add the new region to the
6756 RegionFactory::map_add (nr);
6757 pl->add_region (nr, r->position() + pos);
6760 new_regions.push_front(nr);
6765 /* We might have removed regions, which alters other regions' layering_index,
6766 so we need to do a recursive diff here.
6768 vector<Command*> cmds;
6770 _session->add_commands (cmds);
6772 _session->add_command (new StatefulDiffCommand (pl));
6776 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6777 set_selected_regionview_from_region_list ((*i), Selection::Add);
6783 Editor::place_transient()
6789 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6795 framepos_t where = get_preferred_edit_position();
6797 begin_reversible_command (_("place transient"));
6799 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6800 framepos_t position = (*r)->region()->position();
6801 (*r)->region()->add_transient(where - position);
6804 commit_reversible_command ();
6808 Editor::remove_transient(ArdourCanvas::Item* item)
6814 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6817 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6818 _arv->remove_transient (*(float*) _line->get_data ("position"));
6822 Editor::snap_regions_to_grid ()
6824 list <boost::shared_ptr<Playlist > > used_playlists;
6826 RegionSelection rs = get_regions_from_selection_and_entered ();
6828 if (!_session || rs.empty()) {
6832 begin_reversible_command (_("snap regions to grid"));
6834 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6836 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6838 if (!pl->frozen()) {
6839 /* we haven't seen this playlist before */
6841 /* remember used playlists so we can thaw them later */
6842 used_playlists.push_back(pl);
6846 framepos_t start_frame = (*r)->region()->first_frame ();
6847 snap_to (start_frame);
6848 (*r)->region()->set_position (start_frame);
6851 while (used_playlists.size() > 0) {
6852 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6854 used_playlists.pop_front();
6857 commit_reversible_command ();
6861 Editor::close_region_gaps ()
6863 list <boost::shared_ptr<Playlist > > used_playlists;
6865 RegionSelection rs = get_regions_from_selection_and_entered ();
6867 if (!_session || rs.empty()) {
6871 Dialog dialog (_("Close Region Gaps"));
6874 table.set_spacings (12);
6875 table.set_border_width (12);
6876 Label* l = manage (left_aligned_label (_("Crossfade length")));
6877 table.attach (*l, 0, 1, 0, 1);
6879 SpinButton spin_crossfade (1, 0);
6880 spin_crossfade.set_range (0, 15);
6881 spin_crossfade.set_increments (1, 1);
6882 spin_crossfade.set_value (5);
6883 table.attach (spin_crossfade, 1, 2, 0, 1);
6885 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6887 l = manage (left_aligned_label (_("Pull-back length")));
6888 table.attach (*l, 0, 1, 1, 2);
6890 SpinButton spin_pullback (1, 0);
6891 spin_pullback.set_range (0, 100);
6892 spin_pullback.set_increments (1, 1);
6893 spin_pullback.set_value(30);
6894 table.attach (spin_pullback, 1, 2, 1, 2);
6896 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6898 dialog.get_vbox()->pack_start (table);
6899 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6900 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6903 if (dialog.run () == RESPONSE_CANCEL) {
6907 framepos_t crossfade_len = spin_crossfade.get_value();
6908 framepos_t pull_back_frames = spin_pullback.get_value();
6910 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6911 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6913 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6915 begin_reversible_command (_("close region gaps"));
6918 boost::shared_ptr<Region> last_region;
6920 rs.sort_by_position_and_track();
6922 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6924 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6926 if (!pl->frozen()) {
6927 /* we haven't seen this playlist before */
6929 /* remember used playlists so we can thaw them later */
6930 used_playlists.push_back(pl);
6934 framepos_t position = (*r)->region()->position();
6936 if (idx == 0 || position < last_region->position()){
6937 last_region = (*r)->region();
6942 (*r)->region()->trim_front( (position - pull_back_frames));
6943 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6945 last_region = (*r)->region();
6950 while (used_playlists.size() > 0) {
6951 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6953 used_playlists.pop_front();
6956 commit_reversible_command ();
6960 Editor::tab_to_transient (bool forward)
6962 AnalysisFeatureList positions;
6964 RegionSelection rs = get_regions_from_selection_and_entered ();
6970 framepos_t pos = _session->audible_frame ();
6972 if (!selection->tracks.empty()) {
6974 /* don't waste time searching for transients in duplicate playlists.
6977 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6979 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6981 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6984 boost::shared_ptr<Track> tr = rtv->track();
6986 boost::shared_ptr<Playlist> pl = tr->playlist ();
6988 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6991 positions.push_back (result);
7004 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7005 (*r)->region()->get_transients (positions);
7009 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7012 AnalysisFeatureList::iterator x;
7014 for (x = positions.begin(); x != positions.end(); ++x) {
7020 if (x != positions.end ()) {
7021 _session->request_locate (*x);
7025 AnalysisFeatureList::reverse_iterator x;
7027 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7033 if (x != positions.rend ()) {
7034 _session->request_locate (*x);
7040 Editor::playhead_forward_to_grid ()
7046 framepos_t pos = playhead_cursor->current_frame ();
7047 if (pos < max_framepos - 1) {
7049 snap_to_internal (pos, RoundUpAlways, false);
7050 _session->request_locate (pos);
7056 Editor::playhead_backward_to_grid ()
7062 framepos_t pos = playhead_cursor->current_frame ();
7065 snap_to_internal (pos, RoundDownAlways, false);
7066 _session->request_locate (pos);
7071 Editor::set_track_height (Height h)
7073 TrackSelection& ts (selection->tracks);
7075 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7076 (*x)->set_height_enum (h);
7081 Editor::toggle_tracks_active ()
7083 TrackSelection& ts (selection->tracks);
7085 bool target = false;
7091 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7092 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7096 target = !rtv->_route->active();
7099 rtv->_route->set_active (target, this);
7105 Editor::remove_tracks ()
7107 /* this will delete GUI objects that may be the subject of an event
7108 handler in which this method is called. Defer actual deletion to the
7109 next idle callback, when all event handling is finished.
7111 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7115 Editor::idle_remove_tracks ()
7118 return false; /* do not call again */
7122 Editor::_remove_tracks ()
7124 TrackSelection& ts (selection->tracks);
7130 vector<string> choices;
7134 const char* trackstr;
7136 vector<boost::shared_ptr<Route> > routes;
7137 bool special_bus = false;
7139 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7140 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7144 if (rtv->is_track()) {
7149 routes.push_back (rtv->_route);
7151 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7156 if (special_bus && !Config->get_allow_special_bus_removal()) {
7157 MessageDialog msg (_("That would be bad news ...."),
7161 msg.set_secondary_text (string_compose (_(
7162 "Removing the master or monitor bus is such a bad idea\n\
7163 that %1 is not going to allow it.\n\
7165 If you really want to do this sort of thing\n\
7166 edit your ardour.rc file to set the\n\
7167 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7174 if (ntracks + nbusses == 0) {
7178 trackstr = P_("track", "tracks", ntracks);
7179 busstr = P_("bus", "busses", nbusses);
7183 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7184 "(You may also lose the playlists associated with the %2)\n\n"
7185 "This action cannot be undone, and the session file will be overwritten!"),
7186 ntracks, trackstr, nbusses, busstr);
7188 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7189 "(You may also lose the playlists associated with the %2)\n\n"
7190 "This action cannot be undone, and the session file will be overwritten!"),
7193 } else if (nbusses) {
7194 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7195 "This action cannot be undone, and the session file will be overwritten"),
7199 choices.push_back (_("No, do nothing."));
7200 if (ntracks + nbusses > 1) {
7201 choices.push_back (_("Yes, remove them."));
7203 choices.push_back (_("Yes, remove it."));
7208 title = string_compose (_("Remove %1"), trackstr);
7210 title = string_compose (_("Remove %1"), busstr);
7213 Choice prompter (title, prompt, choices);
7215 if (prompter.run () != 1) {
7220 Session::StateProtector sp (_session);
7221 DisplaySuspender ds;
7222 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7223 _session->remove_route (*x);
7229 Editor::do_insert_time ()
7231 if (selection->tracks.empty()) {
7235 InsertRemoveTimeDialog d (*this);
7236 int response = d.run ();
7238 if (response != RESPONSE_OK) {
7242 if (d.distance() == 0) {
7246 InsertTimeOption opt = d.intersected_region_action ();
7249 get_preferred_edit_position(),
7255 d.move_glued_markers(),
7256 d.move_locked_markers(),
7262 Editor::insert_time (
7263 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7264 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7268 if (Config->get_edit_mode() == Lock) {
7271 bool in_command = false;
7273 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7275 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7279 /* don't operate on any playlist more than once, which could
7280 * happen if "all playlists" is enabled, but there is more
7281 * than 1 track using playlists "from" a given track.
7284 set<boost::shared_ptr<Playlist> > pl;
7286 if (all_playlists) {
7287 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7289 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7290 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7295 if ((*x)->playlist ()) {
7296 pl.insert ((*x)->playlist ());
7300 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7302 (*i)->clear_changes ();
7303 (*i)->clear_owned_changes ();
7305 if (opt == SplitIntersected) {
7309 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7312 begin_reversible_command (_("insert time"));
7315 vector<Command*> cmds;
7317 _session->add_commands (cmds);
7319 _session->add_command (new StatefulDiffCommand (*i));
7323 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7326 begin_reversible_command (_("insert time"));
7329 rtav->route ()->shift (pos, frames);
7336 XMLNode& before (_session->locations()->get_state());
7337 Locations::LocationList copy (_session->locations()->list());
7339 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7341 Locations::LocationList::const_iterator tmp;
7343 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7344 bool const was_locked = (*i)->locked ();
7345 if (locked_markers_too) {
7349 if ((*i)->start() >= pos) {
7350 // move end first, in case we're moving by more than the length of the range
7351 if (!(*i)->is_mark()) {
7352 (*i)->set_end ((*i)->end() + frames);
7354 (*i)->set_start ((*i)->start() + frames);
7366 begin_reversible_command (_("insert time"));
7369 XMLNode& after (_session->locations()->get_state());
7370 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7376 begin_reversible_command (_("insert time"));
7379 XMLNode& before (_session->tempo_map().get_state());
7380 _session->tempo_map().insert_time (pos, frames);
7381 XMLNode& after (_session->tempo_map().get_state());
7382 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7386 commit_reversible_command ();
7391 Editor::do_remove_time ()
7393 if (selection->tracks.empty()) {
7397 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7398 InsertRemoveTimeDialog d (*this, true);
7400 int response = d.run ();
7402 if (response != RESPONSE_OK) {
7406 framecnt_t distance = d.distance();
7408 if (distance == 0) {
7418 d.move_glued_markers(),
7419 d.move_locked_markers(),
7425 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7426 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7428 if (Config->get_edit_mode() == Lock) {
7429 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7432 bool in_command = false;
7434 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7436 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7440 XMLNode &before = pl->get_state();
7442 std::list<AudioRange> rl;
7443 AudioRange ar(pos, pos+frames, 0);
7446 pl->shift (pos, -frames, true, ignore_music_glue);
7449 begin_reversible_command (_("cut time"));
7452 XMLNode &after = pl->get_state();
7454 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7458 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7461 begin_reversible_command (_("cut time"));
7464 rtav->route ()->shift (pos, -frames);
7468 std::list<Location*> loc_kill_list;
7473 XMLNode& before (_session->locations()->get_state());
7474 Locations::LocationList copy (_session->locations()->list());
7476 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7477 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7479 bool const was_locked = (*i)->locked ();
7480 if (locked_markers_too) {
7484 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7485 if ((*i)->end() >= pos
7486 && (*i)->end() < pos+frames
7487 && (*i)->start() >= pos
7488 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7490 loc_kill_list.push_back(*i);
7491 } else { // only start or end is included, try to do the right thing
7492 // move start before moving end, to avoid trying to move the end to before the start
7493 // if we're removing more time than the length of the range
7494 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7495 // start is within cut
7496 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7498 } else if ((*i)->start() >= pos+frames) {
7499 // start (and thus entire range) lies beyond end of cut
7500 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7503 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7504 // end is inside cut
7505 (*i)->set_end (pos); // bring the end to the cut
7507 } else if ((*i)->end() >= pos+frames) {
7508 // end is beyond end of cut
7509 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7514 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7515 loc_kill_list.push_back(*i);
7517 } else if ((*i)->start() >= pos) {
7518 (*i)->set_start ((*i)->start() -frames);
7528 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7529 _session->locations()->remove( *i );
7534 begin_reversible_command (_("cut time"));
7537 XMLNode& after (_session->locations()->get_state());
7538 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7543 XMLNode& before (_session->tempo_map().get_state());
7545 if (_session->tempo_map().remove_time (pos, frames) ) {
7547 begin_reversible_command (_("remove time"));
7550 XMLNode& after (_session->tempo_map().get_state());
7551 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7556 commit_reversible_command ();
7561 Editor::fit_selection ()
7563 if (!selection->tracks.empty()) {
7564 fit_tracks (selection->tracks);
7568 /* no selected tracks - use tracks with selected regions */
7570 if (!selection->regions.empty()) {
7571 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7572 tvl.push_back (&(*r)->get_time_axis_view ());
7578 } else if (internal_editing()) {
7579 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7582 if (entered_track) {
7583 tvl.push_back (entered_track);
7592 Editor::fit_tracks (TrackViewList & tracks)
7594 if (tracks.empty()) {
7598 uint32_t child_heights = 0;
7599 int visible_tracks = 0;
7601 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7603 if (!(*t)->marked_for_display()) {
7607 child_heights += (*t)->effective_height() - (*t)->current_height();
7611 /* compute the per-track height from:
7613 total canvas visible height -
7614 height that will be taken by visible children of selected
7615 tracks - height of the ruler/hscroll area
7617 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7618 double first_y_pos = DBL_MAX;
7620 if (h < TimeAxisView::preset_height (HeightSmall)) {
7621 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7622 /* too small to be displayed */
7626 undo_visual_stack.push_back (current_visual_state (true));
7627 PBD::Unwinder<bool> nsv (no_save_visual, true);
7629 /* build a list of all tracks, including children */
7632 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7634 TimeAxisView::Children c = (*i)->get_child_list ();
7635 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7636 all.push_back (j->get());
7641 // find selection range.
7642 // if someone knows how to user TrackViewList::iterator for this
7644 int selected_top = -1;
7645 int selected_bottom = -1;
7647 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7648 if ((*t)->marked_for_display ()) {
7649 if (tracks.contains(*t)) {
7650 if (selected_top == -1) {
7653 selected_bottom = i;
7659 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7660 if ((*t)->marked_for_display ()) {
7661 if (tracks.contains(*t)) {
7662 (*t)->set_height (h);
7663 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7665 if (i > selected_top && i < selected_bottom) {
7666 hide_track_in_display (*t);
7673 set the controls_layout height now, because waiting for its size
7674 request signal handler will cause the vertical adjustment setting to fail
7677 controls_layout.property_height () = _full_canvas_height;
7678 vertical_adjustment.set_value (first_y_pos);
7680 redo_visual_stack.push_back (current_visual_state (true));
7682 visible_tracks_selector.set_text (_("Sel"));
7686 Editor::save_visual_state (uint32_t n)
7688 while (visual_states.size() <= n) {
7689 visual_states.push_back (0);
7692 if (visual_states[n] != 0) {
7693 delete visual_states[n];
7696 visual_states[n] = current_visual_state (true);
7701 Editor::goto_visual_state (uint32_t n)
7703 if (visual_states.size() <= n) {
7707 if (visual_states[n] == 0) {
7711 use_visual_state (*visual_states[n]);
7715 Editor::start_visual_state_op (uint32_t n)
7717 save_visual_state (n);
7719 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7721 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7722 pup->set_text (buf);
7727 Editor::cancel_visual_state_op (uint32_t n)
7729 goto_visual_state (n);
7733 Editor::toggle_region_mute ()
7735 if (_ignore_region_action) {
7739 RegionSelection rs = get_regions_from_selection_and_entered ();
7745 if (rs.size() > 1) {
7746 begin_reversible_command (_("mute regions"));
7748 begin_reversible_command (_("mute region"));
7751 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7753 (*i)->region()->playlist()->clear_changes ();
7754 (*i)->region()->set_muted (!(*i)->region()->muted ());
7755 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7759 commit_reversible_command ();
7763 Editor::combine_regions ()
7765 /* foreach track with selected regions, take all selected regions
7766 and join them into a new region containing the subregions (as a
7770 typedef set<RouteTimeAxisView*> RTVS;
7773 if (selection->regions.empty()) {
7777 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7778 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7781 tracks.insert (rtv);
7785 begin_reversible_command (_("combine regions"));
7787 vector<RegionView*> new_selection;
7789 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7792 if ((rv = (*i)->combine_regions ()) != 0) {
7793 new_selection.push_back (rv);
7797 selection->clear_regions ();
7798 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7799 selection->add (*i);
7802 commit_reversible_command ();
7806 Editor::uncombine_regions ()
7808 typedef set<RouteTimeAxisView*> RTVS;
7811 if (selection->regions.empty()) {
7815 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7816 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7819 tracks.insert (rtv);
7823 begin_reversible_command (_("uncombine regions"));
7825 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7826 (*i)->uncombine_regions ();
7829 commit_reversible_command ();
7833 Editor::toggle_midi_input_active (bool flip_others)
7836 boost::shared_ptr<RouteList> rl (new RouteList);
7838 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7839 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7845 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7848 rl->push_back (rtav->route());
7849 onoff = !mt->input_active();
7853 _session->set_exclusive_input_active (rl, onoff, flip_others);
7860 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7862 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7863 lock_dialog->get_vbox()->pack_start (*padlock);
7865 ArdourButton* b = manage (new ArdourButton);
7866 b->set_name ("lock button");
7867 b->set_text (_("Click to unlock"));
7868 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7869 lock_dialog->get_vbox()->pack_start (*b);
7871 lock_dialog->get_vbox()->show_all ();
7872 lock_dialog->set_size_request (200, 200);
7875 delete _main_menu_disabler;
7876 _main_menu_disabler = new MainMenuDisabler;
7878 lock_dialog->present ();
7884 lock_dialog->hide ();
7886 delete _main_menu_disabler;
7888 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7889 start_lock_event_timing ();
7894 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7896 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7900 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7902 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7903 Gtkmm2ext::UI::instance()->flush_pending ();
7907 Editor::bring_all_sources_into_session ()
7914 ArdourDialog w (_("Moving embedded files into session folder"));
7915 w.get_vbox()->pack_start (msg);
7918 /* flush all pending GUI events because we're about to start copying
7922 Gtkmm2ext::UI::instance()->flush_pending ();
7926 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));