2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "audio_region_view.h"
65 #include "audio_streamview.h"
66 #include "audio_time_axis.h"
67 #include "automation_region_view.h"
68 #include "automation_time_axis.h"
69 #include "control_point.h"
73 #include "editor_cursors.h"
74 #include "editor_drag.h"
75 #include "editor_regions.h"
76 #include "editor_routes.h"
77 #include "gui_thread.h"
78 #include "insert_remove_time_dialog.h"
79 #include "interthread_progress_window.h"
80 #include "item_counts.h"
82 #include "midi_region_view.h"
83 #include "mixer_strip.h"
84 #include "mouse_cursors.h"
85 #include "normalize_dialog.h"
87 #include "paste_context.h"
88 #include "patch_change_dialog.h"
89 #include "quantize_dialog.h"
90 #include "region_gain_line.h"
91 #include "rgb_macros.h"
92 #include "route_time_axis.h"
93 #include "selection.h"
94 #include "selection_templates.h"
95 #include "streamview.h"
96 #include "strip_silence_dialog.h"
97 #include "time_axis_view.h"
98 #include "transpose_dialog.h"
99 #include "transform_dialog.h"
100 #include "ui_config.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
112 /***********************************************************************
114 ***********************************************************************/
117 Editor::undo (uint32_t n)
119 if (_drags->active ()) {
125 if (_session->undo_depth() == 0) {
126 undo_action->set_sensitive(false);
128 redo_action->set_sensitive(true);
129 begin_selection_op_history ();
134 Editor::redo (uint32_t n)
136 if (_drags->active ()) {
142 if (_session->redo_depth() == 0) {
143 redo_action->set_sensitive(false);
145 undo_action->set_sensitive(true);
146 begin_selection_op_history ();
151 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
155 RegionSelection pre_selected_regions = selection->regions;
156 bool working_on_selection = !pre_selected_regions.empty();
158 list<boost::shared_ptr<Playlist> > used_playlists;
159 list<RouteTimeAxisView*> used_trackviews;
161 if (regions.empty()) {
165 begin_reversible_command (_("split"));
167 // if splitting a single region, and snap-to is using
168 // region boundaries, don't pay attention to them
170 if (regions.size() == 1) {
171 switch (_snap_type) {
172 case SnapToRegionStart:
173 case SnapToRegionSync:
174 case SnapToRegionEnd:
183 EditorFreeze(); /* Emit Signal */
186 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
188 RegionSelection::iterator tmp;
190 /* XXX this test needs to be more complicated, to make sure we really
191 have something to split.
194 if (!(*a)->region()->covers (where)) {
202 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
210 /* we haven't seen this playlist before */
212 /* remember used playlists so we can thaw them later */
213 used_playlists.push_back(pl);
215 TimeAxisView& tv = (*a)->get_time_axis_view();
216 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
218 used_trackviews.push_back (rtv);
225 pl->clear_changes ();
226 pl->split_region ((*a)->region(), where);
227 _session->add_command (new StatefulDiffCommand (pl));
233 latest_regionviews.clear ();
235 vector<sigc::connection> region_added_connections;
237 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
238 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
241 while (used_playlists.size() > 0) {
242 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
244 used_playlists.pop_front();
247 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
252 EditorThaw(); /* Emit Signal */
255 if (working_on_selection) {
256 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
258 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
259 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
260 /* There are three classes of regions that we might want selected after
261 splitting selected regions:
262 - regions selected before the split operation, and unaffected by it
263 - newly-created regions before the split
264 - newly-created regions after the split
267 if (rsas & Existing) {
268 // region selections that existed before the split.
269 selection->add ( pre_selected_regions );
272 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
273 if ((*ri)->region()->position() < where) {
274 // new regions created before the split
275 if (rsas & NewlyCreatedLeft) {
276 selection->add (*ri);
279 // new regions created after the split
280 if (rsas & NewlyCreatedRight) {
281 selection->add (*ri);
285 _ignore_follow_edits = false;
287 _ignore_follow_edits = true;
288 if( working_on_selection ) {
289 selection->add (latest_regionviews); //these are the new regions created after the split
291 _ignore_follow_edits = false;
294 commit_reversible_command ();
297 /** Move one extreme of the current range selection. If more than one range is selected,
298 * the start of the earliest range or the end of the latest range is moved.
300 * @param move_end true to move the end of the current range selection, false to move
302 * @param next true to move the extreme to the next region boundary, false to move to
306 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
308 if (selection->time.start() == selection->time.end_frame()) {
312 framepos_t start = selection->time.start ();
313 framepos_t end = selection->time.end_frame ();
315 /* the position of the thing we may move */
316 framepos_t pos = move_end ? end : start;
317 int dir = next ? 1 : -1;
319 /* so we don't find the current region again */
320 if (dir > 0 || pos > 0) {
324 framepos_t const target = get_region_boundary (pos, dir, true, false);
339 begin_reversible_selection_op (_("alter selection"));
340 selection->set_preserving_all_ranges (start, end);
341 commit_reversible_selection_op ();
345 Editor::nudge_forward_release (GdkEventButton* ev)
347 if (ev->state & Keyboard::PrimaryModifier) {
348 nudge_forward (false, true);
350 nudge_forward (false, false);
356 Editor::nudge_backward_release (GdkEventButton* ev)
358 if (ev->state & Keyboard::PrimaryModifier) {
359 nudge_backward (false, true);
361 nudge_backward (false, false);
368 Editor::nudge_forward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions forward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
393 r->set_position (r->position() + distance);
394 _session->add_command (new StatefulDiffCommand (r));
397 commit_reversible_command ();
400 } else if (!force_playhead && !selection->markers.empty()) {
403 bool in_command = false;
405 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
407 Location* loc = find_location_from_marker ((*i), is_start);
411 XMLNode& before (loc->get_state());
414 distance = get_nudge_distance (loc->start(), next_distance);
416 distance = next_distance;
418 if (max_framepos - distance > loc->start() + loc->length()) {
419 loc->set_start (loc->start() + distance);
421 loc->set_start (max_framepos - loc->length());
424 distance = get_nudge_distance (loc->end(), next_distance);
426 distance = next_distance;
428 if (max_framepos - distance > loc->end()) {
429 loc->set_end (loc->end() + distance);
431 loc->set_end (max_framepos);
435 begin_reversible_command (_("nudge location forward"));
438 XMLNode& after (loc->get_state());
439 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
444 commit_reversible_command ();
447 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
448 _session->request_locate (playhead_cursor->current_frame () + distance);
453 Editor::nudge_backward (bool next, bool force_playhead)
456 framepos_t next_distance;
462 RegionSelection rs = get_regions_from_selection_and_entered ();
464 if (!force_playhead && !rs.empty()) {
466 begin_reversible_command (_("nudge regions backward"));
468 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
469 boost::shared_ptr<Region> r ((*i)->region());
471 distance = get_nudge_distance (r->position(), next_distance);
474 distance = next_distance;
479 if (r->position() > distance) {
480 r->set_position (r->position() - distance);
484 _session->add_command (new StatefulDiffCommand (r));
487 commit_reversible_command ();
489 } else if (!force_playhead && !selection->markers.empty()) {
492 bool in_command = false;
494 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
496 Location* loc = find_location_from_marker ((*i), is_start);
500 XMLNode& before (loc->get_state());
503 distance = get_nudge_distance (loc->start(), next_distance);
505 distance = next_distance;
507 if (distance < loc->start()) {
508 loc->set_start (loc->start() - distance);
513 distance = get_nudge_distance (loc->end(), next_distance);
516 distance = next_distance;
519 if (distance < loc->end() - loc->length()) {
520 loc->set_end (loc->end() - distance);
522 loc->set_end (loc->length());
526 begin_reversible_command (_("nudge location forward"));
529 XMLNode& after (loc->get_state());
530 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
534 commit_reversible_command ();
539 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
541 if (playhead_cursor->current_frame () > distance) {
542 _session->request_locate (playhead_cursor->current_frame () - distance);
544 _session->goto_start();
550 Editor::nudge_forward_capture_offset ()
552 RegionSelection rs = get_regions_from_selection_and_entered ();
554 if (!_session || rs.empty()) {
558 begin_reversible_command (_("nudge forward"));
560 framepos_t const distance = _session->worst_output_latency();
562 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
563 boost::shared_ptr<Region> r ((*i)->region());
566 r->set_position (r->position() + distance);
567 _session->add_command(new StatefulDiffCommand (r));
570 commit_reversible_command ();
574 Editor::nudge_backward_capture_offset ()
576 RegionSelection rs = get_regions_from_selection_and_entered ();
578 if (!_session || rs.empty()) {
582 begin_reversible_command (_("nudge backward"));
584 framepos_t const distance = _session->worst_output_latency();
586 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
587 boost::shared_ptr<Region> r ((*i)->region());
591 if (r->position() > distance) {
592 r->set_position (r->position() - distance);
596 _session->add_command(new StatefulDiffCommand (r));
599 commit_reversible_command ();
602 struct RegionSelectionPositionSorter {
603 bool operator() (RegionView* a, RegionView* b) {
604 return a->region()->position() < b->region()->position();
609 Editor::sequence_regions ()
612 framepos_t r_end_prev;
620 RegionSelection rs = get_regions_from_selection_and_entered ();
621 rs.sort(RegionSelectionPositionSorter());
625 bool in_command = false;
627 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
628 boost::shared_ptr<Region> r ((*i)->region());
636 if(r->position_locked())
643 r->set_position(r_end_prev);
647 begin_reversible_command (_("sequence regions"));
650 _session->add_command (new StatefulDiffCommand (r));
652 r_end=r->position() + r->length();
658 commit_reversible_command ();
667 Editor::move_to_start ()
669 _session->goto_start ();
673 Editor::move_to_end ()
676 _session->request_locate (_session->current_end_frame());
680 Editor::build_region_boundary_cache ()
683 vector<RegionPoint> interesting_points;
684 boost::shared_ptr<Region> r;
685 TrackViewList tracks;
688 region_boundary_cache.clear ();
694 switch (_snap_type) {
695 case SnapToRegionStart:
696 interesting_points.push_back (Start);
698 case SnapToRegionEnd:
699 interesting_points.push_back (End);
701 case SnapToRegionSync:
702 interesting_points.push_back (SyncPoint);
704 case SnapToRegionBoundary:
705 interesting_points.push_back (Start);
706 interesting_points.push_back (End);
709 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
710 abort(); /*NOTREACHED*/
714 TimeAxisView *ontrack = 0;
717 if (!selection->tracks.empty()) {
718 tlist = selection->tracks.filter_to_unique_playlists ();
720 tlist = track_views.filter_to_unique_playlists ();
723 while (pos < _session->current_end_frame() && !at_end) {
726 framepos_t lpos = max_framepos;
728 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
730 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
731 if (*p == interesting_points.back()) {
734 /* move to next point type */
740 rpos = r->first_frame();
744 rpos = r->last_frame();
748 rpos = r->sync_position ();
756 RouteTimeAxisView *rtav;
758 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
759 if (rtav->track() != 0) {
760 speed = rtav->track()->speed();
764 rpos = track_frame_to_session_frame (rpos, speed);
770 /* prevent duplicates, but we don't use set<> because we want to be able
774 vector<framepos_t>::iterator ri;
776 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
782 if (ri == region_boundary_cache.end()) {
783 region_boundary_cache.push_back (rpos);
790 /* finally sort to be sure that the order is correct */
792 sort (region_boundary_cache.begin(), region_boundary_cache.end());
795 boost::shared_ptr<Region>
796 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
798 TrackViewList::iterator i;
799 framepos_t closest = max_framepos;
800 boost::shared_ptr<Region> ret;
804 framepos_t track_frame;
805 RouteTimeAxisView *rtav;
807 for (i = tracks.begin(); i != tracks.end(); ++i) {
810 boost::shared_ptr<Region> r;
813 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
814 if (rtav->track()!=0)
815 track_speed = rtav->track()->speed();
818 track_frame = session_frame_to_track_frame(frame, track_speed);
820 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
826 rpos = r->first_frame ();
830 rpos = r->last_frame ();
834 rpos = r->sync_position ();
838 // rpos is a "track frame", converting it to "_session frame"
839 rpos = track_frame_to_session_frame(rpos, track_speed);
842 distance = rpos - frame;
844 distance = frame - rpos;
847 if (distance < closest) {
859 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
861 framecnt_t distance = max_framepos;
862 framepos_t current_nearest = -1;
864 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
865 framepos_t contender;
868 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
874 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
878 d = ::llabs (pos - contender);
881 current_nearest = contender;
886 return current_nearest;
890 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
895 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
897 if (!selection->tracks.empty()) {
899 target = find_next_region_boundary (pos, dir, selection->tracks);
903 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
904 get_onscreen_tracks (tvl);
905 target = find_next_region_boundary (pos, dir, tvl);
907 target = find_next_region_boundary (pos, dir, track_views);
913 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
914 get_onscreen_tracks (tvl);
915 target = find_next_region_boundary (pos, dir, tvl);
917 target = find_next_region_boundary (pos, dir, track_views);
925 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
927 framepos_t pos = playhead_cursor->current_frame ();
934 // so we don't find the current region again..
935 if (dir > 0 || pos > 0) {
939 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
943 _session->request_locate (target);
947 Editor::cursor_to_next_region_boundary (bool with_selection)
949 cursor_to_region_boundary (with_selection, 1);
953 Editor::cursor_to_previous_region_boundary (bool with_selection)
955 cursor_to_region_boundary (with_selection, -1);
959 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
961 boost::shared_ptr<Region> r;
962 framepos_t pos = cursor->current_frame ();
968 TimeAxisView *ontrack = 0;
970 // so we don't find the current region again..
974 if (!selection->tracks.empty()) {
976 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
978 } else if (clicked_axisview) {
981 t.push_back (clicked_axisview);
983 r = find_next_region (pos, point, dir, t, &ontrack);
987 r = find_next_region (pos, point, dir, track_views, &ontrack);
996 pos = r->first_frame ();
1000 pos = r->last_frame ();
1004 pos = r->sync_position ();
1009 RouteTimeAxisView *rtav;
1011 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1012 if (rtav->track() != 0) {
1013 speed = rtav->track()->speed();
1017 pos = track_frame_to_session_frame(pos, speed);
1019 if (cursor == playhead_cursor) {
1020 _session->request_locate (pos);
1022 cursor->set_position (pos);
1027 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1029 cursor_to_region_point (cursor, point, 1);
1033 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1035 cursor_to_region_point (cursor, point, -1);
1039 Editor::cursor_to_selection_start (EditorCursor *cursor)
1043 switch (mouse_mode) {
1045 if (!selection->regions.empty()) {
1046 pos = selection->regions.start();
1051 if (!selection->time.empty()) {
1052 pos = selection->time.start ();
1060 if (cursor == playhead_cursor) {
1061 _session->request_locate (pos);
1063 cursor->set_position (pos);
1068 Editor::cursor_to_selection_end (EditorCursor *cursor)
1072 switch (mouse_mode) {
1074 if (!selection->regions.empty()) {
1075 pos = selection->regions.end_frame();
1080 if (!selection->time.empty()) {
1081 pos = selection->time.end_frame ();
1089 if (cursor == playhead_cursor) {
1090 _session->request_locate (pos);
1092 cursor->set_position (pos);
1097 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1107 if (selection->markers.empty()) {
1111 if (!mouse_frame (mouse, ignored)) {
1115 add_location_mark (mouse);
1118 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1122 framepos_t pos = loc->start();
1124 // so we don't find the current region again..
1125 if (dir > 0 || pos > 0) {
1129 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1133 loc->move_to (target);
1137 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1139 selected_marker_to_region_boundary (with_selection, 1);
1143 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1145 selected_marker_to_region_boundary (with_selection, -1);
1149 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1151 boost::shared_ptr<Region> r;
1156 if (!_session || selection->markers.empty()) {
1160 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1164 TimeAxisView *ontrack = 0;
1168 // so we don't find the current region again..
1172 if (!selection->tracks.empty()) {
1174 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1178 r = find_next_region (pos, point, dir, track_views, &ontrack);
1187 pos = r->first_frame ();
1191 pos = r->last_frame ();
1195 pos = r->adjust_to_sync (r->first_frame());
1200 RouteTimeAxisView *rtav;
1202 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1203 if (rtav->track() != 0) {
1204 speed = rtav->track()->speed();
1208 pos = track_frame_to_session_frame(pos, speed);
1214 Editor::selected_marker_to_next_region_point (RegionPoint point)
1216 selected_marker_to_region_point (point, 1);
1220 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1222 selected_marker_to_region_point (point, -1);
1226 Editor::selected_marker_to_selection_start ()
1232 if (!_session || selection->markers.empty()) {
1236 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1240 switch (mouse_mode) {
1242 if (!selection->regions.empty()) {
1243 pos = selection->regions.start();
1248 if (!selection->time.empty()) {
1249 pos = selection->time.start ();
1261 Editor::selected_marker_to_selection_end ()
1267 if (!_session || selection->markers.empty()) {
1271 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1275 switch (mouse_mode) {
1277 if (!selection->regions.empty()) {
1278 pos = selection->regions.end_frame();
1283 if (!selection->time.empty()) {
1284 pos = selection->time.end_frame ();
1296 Editor::scroll_playhead (bool forward)
1298 framepos_t pos = playhead_cursor->current_frame ();
1299 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1302 if (pos == max_framepos) {
1306 if (pos < max_framepos - delta) {
1325 _session->request_locate (pos);
1329 Editor::cursor_align (bool playhead_to_edit)
1335 if (playhead_to_edit) {
1337 if (selection->markers.empty()) {
1341 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1344 /* move selected markers to playhead */
1346 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1349 Location* loc = find_location_from_marker (*i, ignored);
1351 if (loc->is_mark()) {
1352 loc->set_start (playhead_cursor->current_frame ());
1354 loc->set (playhead_cursor->current_frame (),
1355 playhead_cursor->current_frame () + loc->length());
1362 Editor::scroll_backward (float pages)
1364 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1365 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1368 if (leftmost_frame < cnt) {
1371 frame = leftmost_frame - cnt;
1374 reset_x_origin (frame);
1378 Editor::scroll_forward (float pages)
1380 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1381 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1384 if (max_framepos - cnt < leftmost_frame) {
1385 frame = max_framepos - cnt;
1387 frame = leftmost_frame + cnt;
1390 reset_x_origin (frame);
1394 Editor::scroll_tracks_down ()
1396 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1397 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1398 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1401 vertical_adjustment.set_value (vert_value);
1405 Editor::scroll_tracks_up ()
1407 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1411 Editor::scroll_tracks_down_line ()
1413 double vert_value = vertical_adjustment.get_value() + 60;
1415 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1416 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1419 vertical_adjustment.set_value (vert_value);
1423 Editor::scroll_tracks_up_line ()
1425 reset_y_origin (vertical_adjustment.get_value() - 60);
1429 Editor::scroll_down_one_track (bool skip_child_views)
1431 TrackViewList::reverse_iterator next = track_views.rend();
1432 const double top_of_trackviews = vertical_adjustment.get_value();
1434 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1435 if ((*t)->hidden()) {
1439 /* If this is the upper-most visible trackview, we want to display
1440 * the one above it (next)
1442 * Note that covers_y_position() is recursive and includes child views
1444 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1447 if (skip_child_views) {
1450 /* automation lane (one level, non-recursive)
1452 * - if no automation lane exists -> move to next tack
1453 * - if the first (here: bottom-most) matches -> move to next tack
1454 * - if no y-axis match is found -> the current track is at the top
1455 * -> move to last (here: top-most) automation lane
1457 TimeAxisView::Children kids = (*t)->get_child_list();
1458 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1460 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1461 if ((*ci)->hidden()) {
1465 std::pair<TimeAxisView*,double> dev;
1466 dev = (*ci)->covers_y_position (top_of_trackviews);
1468 /* some automation lane is currently at the top */
1469 if (ci == kids.rbegin()) {
1470 /* first (bottom-most) autmation lane is at the top.
1471 * -> move to next track
1480 if (nkid != kids.rend()) {
1481 ensure_time_axis_view_is_visible (**nkid, true);
1489 /* move to the track below the first one that covers the */
1491 if (next != track_views.rend()) {
1492 ensure_time_axis_view_is_visible (**next, true);
1500 Editor::scroll_up_one_track (bool skip_child_views)
1502 TrackViewList::iterator prev = track_views.end();
1503 double top_of_trackviews = vertical_adjustment.get_value ();
1505 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1507 if ((*t)->hidden()) {
1511 /* find the trackview at the top of the trackview group
1513 * Note that covers_y_position() is recursive and includes child views
1515 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1518 if (skip_child_views) {
1521 /* automation lane (one level, non-recursive)
1523 * - if no automation lane exists -> move to prev tack
1524 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1525 * (actually last automation lane of previous track, see below)
1526 * - if first (top-most) lane is at the top -> move to this track
1527 * - else move up one lane
1529 TimeAxisView::Children kids = (*t)->get_child_list();
1530 TimeAxisView::Children::iterator pkid = kids.end();
1532 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1533 if ((*ci)->hidden()) {
1537 std::pair<TimeAxisView*,double> dev;
1538 dev = (*ci)->covers_y_position (top_of_trackviews);
1540 /* some automation lane is currently at the top */
1541 if (ci == kids.begin()) {
1542 /* first (top-most) autmation lane is at the top.
1543 * jump directly to this track's top
1545 ensure_time_axis_view_is_visible (**t, true);
1548 else if (pkid != kids.end()) {
1549 /* some other automation lane is at the top.
1550 * move up to prev automation lane.
1552 ensure_time_axis_view_is_visible (**pkid, true);
1555 assert(0); // not reached
1566 if (prev != track_views.end()) {
1567 // move to bottom-most automation-lane of the previous track
1568 TimeAxisView::Children kids = (*prev)->get_child_list();
1569 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1570 if (!skip_child_views) {
1571 // find the last visible lane
1572 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1573 if (!(*ci)->hidden()) {
1579 if (pkid != kids.rend()) {
1580 ensure_time_axis_view_is_visible (**pkid, true);
1582 ensure_time_axis_view_is_visible (**prev, true);
1593 Editor::tav_zoom_step (bool coarser)
1595 DisplaySuspender ds;
1599 if (selection->tracks.empty()) {
1602 ts = &selection->tracks;
1605 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1606 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1607 tv->step_height (coarser);
1612 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1614 DisplaySuspender ds;
1618 if (selection->tracks.empty() || force_all) {
1621 ts = &selection->tracks;
1624 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1625 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1626 uint32_t h = tv->current_height ();
1631 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1636 tv->set_height (h + 5);
1643 Editor::temporal_zoom_step (bool coarser)
1645 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1647 framecnt_t nspp = samples_per_pixel;
1655 temporal_zoom (nspp);
1659 Editor::temporal_zoom (framecnt_t fpp)
1665 framepos_t current_page = current_page_samples();
1666 framepos_t current_leftmost = leftmost_frame;
1667 framepos_t current_rightmost;
1668 framepos_t current_center;
1669 framepos_t new_page_size;
1670 framepos_t half_page_size;
1671 framepos_t leftmost_after_zoom = 0;
1673 bool in_track_canvas;
1677 if (fpp == samples_per_pixel) {
1681 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1682 // segfaults for lack of memory. If somebody decides this is not high enough I
1683 // believe it can be raisen to higher values but some limit must be in place.
1685 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1686 // all of which is used for the editor track displays. The whole day
1687 // would be 4147200000 samples, so 2592000 samples per pixel.
1689 nfpp = min (fpp, (framecnt_t) 2592000);
1690 nfpp = max ((framecnt_t) 1, nfpp);
1692 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1693 half_page_size = new_page_size / 2;
1695 switch (zoom_focus) {
1697 leftmost_after_zoom = current_leftmost;
1700 case ZoomFocusRight:
1701 current_rightmost = leftmost_frame + current_page;
1702 if (current_rightmost < new_page_size) {
1703 leftmost_after_zoom = 0;
1705 leftmost_after_zoom = current_rightmost - new_page_size;
1709 case ZoomFocusCenter:
1710 current_center = current_leftmost + (current_page/2);
1711 if (current_center < half_page_size) {
1712 leftmost_after_zoom = 0;
1714 leftmost_after_zoom = current_center - half_page_size;
1718 case ZoomFocusPlayhead:
1719 /* centre playhead */
1720 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1723 leftmost_after_zoom = 0;
1724 } else if (l > max_framepos) {
1725 leftmost_after_zoom = max_framepos - new_page_size;
1727 leftmost_after_zoom = (framepos_t) l;
1731 case ZoomFocusMouse:
1732 /* try to keep the mouse over the same point in the display */
1734 if (!mouse_frame (where, in_track_canvas)) {
1735 /* use playhead instead */
1736 where = playhead_cursor->current_frame ();
1738 if (where < half_page_size) {
1739 leftmost_after_zoom = 0;
1741 leftmost_after_zoom = where - half_page_size;
1746 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1749 leftmost_after_zoom = 0;
1750 } else if (l > max_framepos) {
1751 leftmost_after_zoom = max_framepos - new_page_size;
1753 leftmost_after_zoom = (framepos_t) l;
1760 /* try to keep the edit point in the same place */
1761 where = get_preferred_edit_position ();
1765 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1768 leftmost_after_zoom = 0;
1769 } else if (l > max_framepos) {
1770 leftmost_after_zoom = max_framepos - new_page_size;
1772 leftmost_after_zoom = (framepos_t) l;
1776 /* edit point not defined */
1783 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1785 reposition_and_zoom (leftmost_after_zoom, nfpp);
1789 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1791 /* this func helps make sure we leave a little space
1792 at each end of the editor so that the zoom doesn't fit the region
1793 precisely to the screen.
1796 GdkScreen* screen = gdk_screen_get_default ();
1797 const gint pixwidth = gdk_screen_get_width (screen);
1798 const gint mmwidth = gdk_screen_get_width_mm (screen);
1799 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1800 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1802 const framepos_t range = end - start;
1803 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1804 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1806 if (start > extra_samples) {
1807 start -= extra_samples;
1812 if (max_framepos - extra_samples > end) {
1813 end += extra_samples;
1820 Editor::temporal_zoom_region (bool both_axes)
1822 framepos_t start = max_framepos;
1824 set<TimeAxisView*> tracks;
1826 if ( !get_selection_extents(start, end) )
1829 calc_extra_zoom_edges (start, end);
1831 /* if we're zooming on both axes we need to save track heights etc.
1834 undo_visual_stack.push_back (current_visual_state (both_axes));
1836 PBD::Unwinder<bool> nsv (no_save_visual, true);
1838 temporal_zoom_by_frame (start, end);
1841 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1843 /* set visible track heights appropriately */
1845 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1846 (*t)->set_height (per_track_height);
1849 /* hide irrelevant tracks */
1851 DisplaySuspender ds;
1853 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1854 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1855 hide_track_in_display (*i);
1859 vertical_adjustment.set_value (0.0);
1862 redo_visual_stack.push_back (current_visual_state (both_axes));
1867 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1869 start = max_framepos;
1873 //ToDo: if notes are selected, set extents to that selection
1875 //ToDo: if control points are selected, set extents to that selection
1877 if ( !selection->regions.empty() ) {
1878 RegionSelection rs = get_regions_from_selection_and_entered ();
1880 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1882 if ((*i)->region()->position() < start) {
1883 start = (*i)->region()->position();
1886 if ((*i)->region()->last_frame() + 1 > end) {
1887 end = (*i)->region()->last_frame() + 1;
1891 } else if (!selection->time.empty()) {
1892 start = selection->time.start();
1893 end = selection->time.end_frame();
1895 ret = false; //no selection found
1898 if ((start == 0 && end == 0) || end < start) {
1907 Editor::temporal_zoom_selection (bool both_axes)
1909 if (!selection) return;
1911 //ToDo: if notes are selected, zoom to that
1913 //ToDo: if control points are selected, zoom to that
1915 //if region(s) are selected, zoom to that
1916 if ( !selection->regions.empty() )
1917 temporal_zoom_region (both_axes);
1919 //if a range is selected, zoom to that
1920 if (!selection->time.empty()) {
1922 framepos_t start, end;
1923 if (get_selection_extents (start, end)) {
1924 calc_extra_zoom_edges(start, end);
1925 temporal_zoom_by_frame (start, end);
1935 Editor::temporal_zoom_session ()
1937 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1940 framecnt_t start = _session->current_start_frame();
1941 framecnt_t end = _session->current_end_frame();
1943 if (_session->actively_recording () ) {
1944 framepos_t cur = playhead_cursor->current_frame ();
1946 /* recording beyond the end marker; zoom out
1947 * by 5 seconds more so that if 'follow
1948 * playhead' is active we don't immediately
1951 end = cur + _session->frame_rate() * 5;
1955 if ((start == 0 && end == 0) || end < start) {
1959 calc_extra_zoom_edges(start, end);
1961 temporal_zoom_by_frame (start, end);
1966 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1968 if (!_session) return;
1970 if ((start == 0 && end == 0) || end < start) {
1974 framepos_t range = end - start;
1976 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1978 framepos_t new_page = range;
1979 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1980 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1982 if (new_leftmost > middle) {
1986 if (new_leftmost < 0) {
1990 reposition_and_zoom (new_leftmost, new_fpp);
1994 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2000 framecnt_t range_before = frame - leftmost_frame;
2004 if (samples_per_pixel <= 1) {
2007 new_spp = samples_per_pixel + (samples_per_pixel/2);
2009 range_before += range_before/2;
2011 if (samples_per_pixel >= 1) {
2012 new_spp = samples_per_pixel - (samples_per_pixel/2);
2014 /* could bail out here since we cannot zoom any finer,
2015 but leave that to the equality test below
2017 new_spp = samples_per_pixel;
2020 range_before -= range_before/2;
2023 if (new_spp == samples_per_pixel) {
2027 /* zoom focus is automatically taken as @param frame when this
2031 framepos_t new_leftmost = frame - (framepos_t)range_before;
2033 if (new_leftmost > frame) {
2037 if (new_leftmost < 0) {
2041 reposition_and_zoom (new_leftmost, new_spp);
2046 Editor::choose_new_marker_name(string &name) {
2048 if (!UIConfiguration::instance().get_name_new_markers()) {
2049 /* don't prompt user for a new name */
2053 ArdourPrompter dialog (true);
2055 dialog.set_prompt (_("New Name:"));
2057 dialog.set_title (_("New Location Marker"));
2059 dialog.set_name ("MarkNameWindow");
2060 dialog.set_size_request (250, -1);
2061 dialog.set_position (Gtk::WIN_POS_MOUSE);
2063 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2064 dialog.set_initial_text (name);
2068 switch (dialog.run ()) {
2069 case RESPONSE_ACCEPT:
2075 dialog.get_result(name);
2082 Editor::add_location_from_selection ()
2086 if (selection->time.empty()) {
2090 if (_session == 0 || clicked_axisview == 0) {
2094 framepos_t start = selection->time[clicked_selection].start;
2095 framepos_t end = selection->time[clicked_selection].end;
2097 _session->locations()->next_available_name(rangename,"selection");
2098 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2100 begin_reversible_command (_("add marker"));
2102 XMLNode &before = _session->locations()->get_state();
2103 _session->locations()->add (location, true);
2104 XMLNode &after = _session->locations()->get_state();
2105 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2107 commit_reversible_command ();
2111 Editor::add_location_mark (framepos_t where)
2115 select_new_marker = true;
2117 _session->locations()->next_available_name(markername,"mark");
2118 if (!choose_new_marker_name(markername)) {
2121 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2122 begin_reversible_command (_("add marker"));
2124 XMLNode &before = _session->locations()->get_state();
2125 _session->locations()->add (location, true);
2126 XMLNode &after = _session->locations()->get_state();
2127 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2129 commit_reversible_command ();
2133 Editor::set_session_start_from_playhead ()
2139 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2140 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2142 XMLNode &before = loc->get_state();
2144 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2146 XMLNode &after = loc->get_state();
2148 begin_reversible_command (_("Set session start"));
2150 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2152 commit_reversible_command ();
2157 Editor::set_session_end_from_playhead ()
2163 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2164 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2166 XMLNode &before = loc->get_state();
2168 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2170 XMLNode &after = loc->get_state();
2172 begin_reversible_command (_("Set session start"));
2174 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2176 commit_reversible_command ();
2181 Editor::add_location_from_playhead_cursor ()
2183 add_location_mark (_session->audible_frame());
2187 Editor::remove_location_at_playhead_cursor ()
2191 XMLNode &before = _session->locations()->get_state();
2192 bool removed = false;
2194 //find location(s) at this time
2195 Locations::LocationList locs;
2196 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2197 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2198 if ((*i)->is_mark()) {
2199 _session->locations()->remove (*i);
2206 begin_reversible_command (_("remove marker"));
2207 XMLNode &after = _session->locations()->get_state();
2208 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2209 commit_reversible_command ();
2214 /** Add a range marker around each selected region */
2216 Editor::add_locations_from_region ()
2218 RegionSelection rs = get_regions_from_selection_and_entered ();
2223 bool commit = false;
2225 XMLNode &before = _session->locations()->get_state();
2227 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2229 boost::shared_ptr<Region> region = (*i)->region ();
2231 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2233 _session->locations()->add (location, true);
2238 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2239 XMLNode &after = _session->locations()->get_state();
2240 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2241 commit_reversible_command ();
2245 /** Add a single range marker around all selected regions */
2247 Editor::add_location_from_region ()
2249 RegionSelection rs = get_regions_from_selection_and_entered ();
2255 XMLNode &before = _session->locations()->get_state();
2259 if (rs.size() > 1) {
2260 _session->locations()->next_available_name(markername, "regions");
2262 RegionView* rv = *(rs.begin());
2263 boost::shared_ptr<Region> region = rv->region();
2264 markername = region->name();
2267 if (!choose_new_marker_name(markername)) {
2271 // single range spanning all selected
2272 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2273 _session->locations()->add (location, true);
2275 begin_reversible_command (_("add marker"));
2276 XMLNode &after = _session->locations()->get_state();
2277 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2278 commit_reversible_command ();
2284 Editor::jump_forward_to_mark ()
2290 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2296 _session->request_locate (pos, _session->transport_rolling());
2300 Editor::jump_backward_to_mark ()
2306 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2312 _session->request_locate (pos, _session->transport_rolling());
2318 framepos_t const pos = _session->audible_frame ();
2321 _session->locations()->next_available_name (markername, "mark");
2323 if (!choose_new_marker_name (markername)) {
2327 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2331 Editor::clear_markers ()
2334 begin_reversible_command (_("clear markers"));
2336 XMLNode &before = _session->locations()->get_state();
2337 _session->locations()->clear_markers ();
2338 XMLNode &after = _session->locations()->get_state();
2339 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2341 commit_reversible_command ();
2346 Editor::clear_ranges ()
2349 begin_reversible_command (_("clear ranges"));
2351 XMLNode &before = _session->locations()->get_state();
2353 _session->locations()->clear_ranges ();
2355 XMLNode &after = _session->locations()->get_state();
2356 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2358 commit_reversible_command ();
2363 Editor::clear_locations ()
2365 begin_reversible_command (_("clear locations"));
2367 XMLNode &before = _session->locations()->get_state();
2368 _session->locations()->clear ();
2369 XMLNode &after = _session->locations()->get_state();
2370 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2372 commit_reversible_command ();
2376 Editor::unhide_markers ()
2378 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2379 Location *l = (*i).first;
2380 if (l->is_hidden() && l->is_mark()) {
2381 l->set_hidden(false, this);
2387 Editor::unhide_ranges ()
2389 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2390 Location *l = (*i).first;
2391 if (l->is_hidden() && l->is_range_marker()) {
2392 l->set_hidden(false, this);
2397 /* INSERT/REPLACE */
2400 Editor::insert_region_list_selection (float times)
2402 RouteTimeAxisView *tv = 0;
2403 boost::shared_ptr<Playlist> playlist;
2405 if (clicked_routeview != 0) {
2406 tv = clicked_routeview;
2407 } else if (!selection->tracks.empty()) {
2408 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2411 } else if (entered_track != 0) {
2412 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2419 if ((playlist = tv->playlist()) == 0) {
2423 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2428 begin_reversible_command (_("insert region"));
2429 playlist->clear_changes ();
2430 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2431 if (Config->get_edit_mode() == Ripple)
2432 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2434 _session->add_command(new StatefulDiffCommand (playlist));
2435 commit_reversible_command ();
2438 /* BUILT-IN EFFECTS */
2441 Editor::reverse_selection ()
2446 /* GAIN ENVELOPE EDITING */
2449 Editor::edit_envelope ()
2456 Editor::transition_to_rolling (bool fwd)
2462 if (_session->config.get_external_sync()) {
2463 switch (Config->get_sync_source()) {
2467 /* transport controlled by the master */
2472 if (_session->is_auditioning()) {
2473 _session->cancel_audition ();
2477 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2481 Editor::play_from_start ()
2483 _session->request_locate (_session->current_start_frame(), true);
2487 Editor::play_from_edit_point ()
2489 _session->request_locate (get_preferred_edit_position(), true);
2493 Editor::play_from_edit_point_and_return ()
2495 framepos_t start_frame;
2496 framepos_t return_frame;
2498 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2500 if (_session->transport_rolling()) {
2501 _session->request_locate (start_frame, false);
2505 /* don't reset the return frame if its already set */
2507 if ((return_frame = _session->requested_return_frame()) < 0) {
2508 return_frame = _session->audible_frame();
2511 if (start_frame >= 0) {
2512 _session->request_roll_at_and_return (start_frame, return_frame);
2517 Editor::play_selection ()
2519 framepos_t start, end;
2520 if (!get_selection_extents ( start, end))
2523 AudioRange ar (start, end, 0);
2524 list<AudioRange> lar;
2527 _session->request_play_range (&lar, true);
2531 Editor::get_preroll ()
2533 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2538 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2540 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits )
2543 location -= get_preroll();
2545 //don't try to locate before the beginning of time
2549 //if follow_playhead is on, keep the playhead on the screen
2550 if ( _follow_playhead )
2551 if ( location < leftmost_frame )
2552 location = leftmost_frame;
2554 _session->request_locate( location );
2558 Editor::play_with_preroll ()
2561 framepos_t preroll = get_preroll();
2563 framepos_t start, end;
2564 if (!get_selection_extents ( start, end))
2567 if (start > preroll)
2568 start = start - preroll;
2570 end = end + preroll; //"post-roll"
2572 AudioRange ar (start, end, 0);
2573 list<AudioRange> lar;
2576 _session->request_play_range (&lar, true);
2581 Editor::play_location (Location& location)
2583 if (location.start() <= location.end()) {
2587 _session->request_bounded_roll (location.start(), location.end());
2591 Editor::loop_location (Location& location)
2593 if (location.start() <= location.end()) {
2599 if ((tll = transport_loop_location()) != 0) {
2600 tll->set (location.start(), location.end());
2602 // enable looping, reposition and start rolling
2603 _session->request_locate (tll->start(), true);
2604 _session->request_play_loop (true);
2609 Editor::do_layer_operation (LayerOperation op)
2611 if (selection->regions.empty ()) {
2615 bool const multiple = selection->regions.size() > 1;
2619 begin_reversible_command (_("raise regions"));
2621 begin_reversible_command (_("raise region"));
2627 begin_reversible_command (_("raise regions to top"));
2629 begin_reversible_command (_("raise region to top"));
2635 begin_reversible_command (_("lower regions"));
2637 begin_reversible_command (_("lower region"));
2643 begin_reversible_command (_("lower regions to bottom"));
2645 begin_reversible_command (_("lower region"));
2650 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2651 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2652 (*i)->clear_owned_changes ();
2655 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2656 boost::shared_ptr<Region> r = (*i)->region ();
2668 r->lower_to_bottom ();
2672 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2673 vector<Command*> cmds;
2675 _session->add_commands (cmds);
2678 commit_reversible_command ();
2682 Editor::raise_region ()
2684 do_layer_operation (Raise);
2688 Editor::raise_region_to_top ()
2690 do_layer_operation (RaiseToTop);
2694 Editor::lower_region ()
2696 do_layer_operation (Lower);
2700 Editor::lower_region_to_bottom ()
2702 do_layer_operation (LowerToBottom);
2705 /** Show the region editor for the selected regions */
2707 Editor::show_region_properties ()
2709 selection->foreach_regionview (&RegionView::show_region_editor);
2712 /** Show the midi list editor for the selected MIDI regions */
2714 Editor::show_midi_list_editor ()
2716 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2720 Editor::rename_region ()
2722 RegionSelection rs = get_regions_from_selection_and_entered ();
2728 ArdourDialog d (*this, _("Rename Region"), true, false);
2730 Label label (_("New name:"));
2733 hbox.set_spacing (6);
2734 hbox.pack_start (label, false, false);
2735 hbox.pack_start (entry, true, true);
2737 d.get_vbox()->set_border_width (12);
2738 d.get_vbox()->pack_start (hbox, false, false);
2740 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2741 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2743 d.set_size_request (300, -1);
2745 entry.set_text (rs.front()->region()->name());
2746 entry.select_region (0, -1);
2748 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2754 int const ret = d.run();
2758 if (ret != RESPONSE_OK) {
2762 std::string str = entry.get_text();
2763 strip_whitespace_edges (str);
2765 rs.front()->region()->set_name (str);
2766 _regions->redisplay ();
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 ();
4795 framecnt_t const gap = end_frame - start_frame;
4797 begin_reversible_command (Operations::duplicate_region);
4799 selection->clear_regions ();
4801 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4803 boost::shared_ptr<Region> r ((*i)->region());
4805 TimeAxisView& tv = (*i)->get_time_axis_view();
4806 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4807 latest_regionviews.clear ();
4808 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4810 framepos_t const position = end_frame + (r->first_frame() - start_frame);
4811 playlist = (*i)->region()->playlist();
4812 playlist->clear_changes ();
4813 playlist->duplicate (r, position, gap, times);
4814 _session->add_command(new StatefulDiffCommand (playlist));
4818 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4822 selection->set (foo);
4825 commit_reversible_command ();
4829 Editor::duplicate_selection (float times)
4831 if (selection->time.empty() || selection->tracks.empty()) {
4835 boost::shared_ptr<Playlist> playlist;
4836 vector<boost::shared_ptr<Region> > new_regions;
4837 vector<boost::shared_ptr<Region> >::iterator ri;
4839 create_region_from_selection (new_regions);
4841 if (new_regions.empty()) {
4845 ri = new_regions.begin();
4847 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4848 bool in_command = false;
4850 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4851 if ((playlist = (*i)->playlist()) == 0) {
4854 playlist->clear_changes ();
4856 if (clicked_selection) {
4857 end = selection->time[clicked_selection].end;
4859 end = selection->time.end_frame();
4861 playlist->duplicate (*ri, end, times);
4864 begin_reversible_command (_("duplicate selection"));
4867 _session->add_command (new StatefulDiffCommand (playlist));
4870 if (ri == new_regions.end()) {
4876 commit_reversible_command ();
4880 /** Reset all selected points to the relevant default value */
4882 Editor::reset_point_selection ()
4884 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4885 ARDOUR::AutomationList::iterator j = (*i)->model ();
4886 (*j)->value = (*i)->line().the_list()->default_value ();
4891 Editor::center_playhead ()
4893 float const page = _visible_canvas_width * samples_per_pixel;
4894 center_screen_internal (playhead_cursor->current_frame (), page);
4898 Editor::center_edit_point ()
4900 float const page = _visible_canvas_width * samples_per_pixel;
4901 center_screen_internal (get_preferred_edit_position(), page);
4904 /** Caller must begin and commit a reversible command */
4906 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4908 playlist->clear_changes ();
4910 _session->add_command (new StatefulDiffCommand (playlist));
4914 Editor::nudge_track (bool use_edit, bool forwards)
4916 boost::shared_ptr<Playlist> playlist;
4917 framepos_t distance;
4918 framepos_t next_distance;
4922 start = get_preferred_edit_position();
4927 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4931 if (selection->tracks.empty()) {
4935 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4936 bool in_command = false;
4938 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4940 if ((playlist = (*i)->playlist()) == 0) {
4944 playlist->clear_changes ();
4945 playlist->clear_owned_changes ();
4947 playlist->nudge_after (start, distance, forwards);
4950 begin_reversible_command (_("nudge track"));
4953 vector<Command*> cmds;
4955 playlist->rdiff (cmds);
4956 _session->add_commands (cmds);
4958 _session->add_command (new StatefulDiffCommand (playlist));
4962 commit_reversible_command ();
4967 Editor::remove_last_capture ()
4969 vector<string> choices;
4976 if (Config->get_verify_remove_last_capture()) {
4977 prompt = _("Do you really want to destroy the last capture?"
4978 "\n(This is destructive and cannot be undone)");
4980 choices.push_back (_("No, do nothing."));
4981 choices.push_back (_("Yes, destroy it."));
4983 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4985 if (prompter.run () == 1) {
4986 _session->remove_last_capture ();
4987 _regions->redisplay ();
4991 _session->remove_last_capture();
4992 _regions->redisplay ();
4997 Editor::normalize_region ()
5003 RegionSelection rs = get_regions_from_selection_and_entered ();
5009 NormalizeDialog dialog (rs.size() > 1);
5011 if (dialog.run () == RESPONSE_CANCEL) {
5015 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5018 /* XXX: should really only count audio regions here */
5019 int const regions = rs.size ();
5021 /* Make a list of the selected audio regions' maximum amplitudes, and also
5022 obtain the maximum amplitude of them all.
5024 list<double> max_amps;
5026 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5027 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5029 dialog.descend (1.0 / regions);
5030 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5033 /* the user cancelled the operation */
5037 max_amps.push_back (a);
5038 max_amp = max (max_amp, a);
5043 list<double>::const_iterator a = max_amps.begin ();
5044 bool in_command = false;
5046 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5047 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5052 arv->region()->clear_changes ();
5054 double const amp = dialog.normalize_individually() ? *a : max_amp;
5056 arv->audio_region()->normalize (amp, dialog.target ());
5059 begin_reversible_command (_("normalize"));
5062 _session->add_command (new StatefulDiffCommand (arv->region()));
5068 commit_reversible_command ();
5074 Editor::reset_region_scale_amplitude ()
5080 RegionSelection rs = get_regions_from_selection_and_entered ();
5086 bool in_command = false;
5088 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5089 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5092 arv->region()->clear_changes ();
5093 arv->audio_region()->set_scale_amplitude (1.0f);
5096 begin_reversible_command ("reset gain");
5099 _session->add_command (new StatefulDiffCommand (arv->region()));
5103 commit_reversible_command ();
5108 Editor::adjust_region_gain (bool up)
5110 RegionSelection rs = get_regions_from_selection_and_entered ();
5112 if (!_session || rs.empty()) {
5116 bool in_command = false;
5118 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5119 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5124 arv->region()->clear_changes ();
5126 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5134 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5137 begin_reversible_command ("adjust region gain");
5140 _session->add_command (new StatefulDiffCommand (arv->region()));
5144 commit_reversible_command ();
5150 Editor::reverse_region ()
5156 Reverse rev (*_session);
5157 apply_filter (rev, _("reverse regions"));
5161 Editor::strip_region_silence ()
5167 RegionSelection rs = get_regions_from_selection_and_entered ();
5173 std::list<RegionView*> audio_only;
5175 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5176 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5178 audio_only.push_back (arv);
5182 assert (!audio_only.empty());
5184 StripSilenceDialog d (_session, audio_only);
5185 int const r = d.run ();
5189 if (r == Gtk::RESPONSE_OK) {
5190 ARDOUR::AudioIntervalMap silences;
5191 d.silences (silences);
5192 StripSilence s (*_session, silences, d.fade_length());
5193 apply_filter (s, _("strip silence"), &d);
5198 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5200 Evoral::Sequence<Evoral::Beats>::Notes selected;
5201 mrv.selection_as_notelist (selected, true);
5203 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5204 v.push_back (selected);
5206 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5207 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5209 return op (mrv.midi_region()->model(), pos_beats, v);
5213 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5219 bool in_command = false;
5221 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5222 RegionSelection::const_iterator tmp = r;
5225 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5228 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5231 begin_reversible_command (op.name ());
5235 _session->add_command (cmd);
5243 commit_reversible_command ();
5248 Editor::fork_region ()
5250 RegionSelection rs = get_regions_from_selection_and_entered ();
5256 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5257 bool in_command = false;
5261 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5262 RegionSelection::iterator tmp = r;
5265 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5269 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5270 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5271 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5274 begin_reversible_command (_("Fork Region(s)"));
5277 playlist->clear_changes ();
5278 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5279 _session->add_command(new StatefulDiffCommand (playlist));
5281 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5289 commit_reversible_command ();
5294 Editor::quantize_region ()
5297 quantize_regions(get_regions_from_selection_and_entered ());
5302 Editor::quantize_regions (const RegionSelection& rs)
5304 if (rs.n_midi_regions() == 0) {
5308 if (!quantize_dialog) {
5309 quantize_dialog = new QuantizeDialog (*this);
5312 quantize_dialog->present ();
5313 const int r = quantize_dialog->run ();
5314 quantize_dialog->hide ();
5316 if (r == Gtk::RESPONSE_OK) {
5317 Quantize quant (quantize_dialog->snap_start(),
5318 quantize_dialog->snap_end(),
5319 quantize_dialog->start_grid_size(),
5320 quantize_dialog->end_grid_size(),
5321 quantize_dialog->strength(),
5322 quantize_dialog->swing(),
5323 quantize_dialog->threshold());
5325 apply_midi_note_edit_op (quant, rs);
5330 Editor::legatize_region (bool shrink_only)
5333 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5338 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5340 if (rs.n_midi_regions() == 0) {
5344 Legatize legatize(shrink_only);
5345 apply_midi_note_edit_op (legatize, rs);
5349 Editor::transform_region ()
5352 transform_regions(get_regions_from_selection_and_entered ());
5357 Editor::transform_regions (const RegionSelection& rs)
5359 if (rs.n_midi_regions() == 0) {
5363 TransformDialog* td = new TransformDialog();
5366 const int r = td->run();
5369 if (r == Gtk::RESPONSE_OK) {
5370 Transform transform(td->get());
5371 apply_midi_note_edit_op(transform, rs);
5376 Editor::insert_patch_change (bool from_context)
5378 RegionSelection rs = get_regions_from_selection_and_entered ();
5384 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5386 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5387 there may be more than one, but the PatchChangeDialog can only offer
5388 one set of patch menus.
5390 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5392 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5393 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5395 if (d.run() == RESPONSE_CANCEL) {
5399 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5400 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5402 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5403 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5410 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5412 RegionSelection rs = get_regions_from_selection_and_entered ();
5418 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5419 bool in_command = false;
5424 int const N = rs.size ();
5426 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5427 RegionSelection::iterator tmp = r;
5430 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5432 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5435 progress->descend (1.0 / N);
5438 if (arv->audio_region()->apply (filter, progress) == 0) {
5440 playlist->clear_changes ();
5441 playlist->clear_owned_changes ();
5443 if (filter.results.empty ()) {
5445 /* no regions returned; remove the old one */
5446 playlist->remove_region (arv->region ());
5450 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5452 /* first region replaces the old one */
5453 playlist->replace_region (arv->region(), *res, (*res)->position());
5457 while (res != filter.results.end()) {
5458 playlist->add_region (*res, (*res)->position());
5463 /* We might have removed regions, which alters other regions' layering_index,
5464 so we need to do a recursive diff here.
5468 begin_reversible_command (command);
5471 vector<Command*> cmds;
5472 playlist->rdiff (cmds);
5473 _session->add_commands (cmds);
5475 _session->add_command(new StatefulDiffCommand (playlist));
5479 progress->ascend ();
5488 commit_reversible_command ();
5493 Editor::external_edit_region ()
5499 Editor::reset_region_gain_envelopes ()
5501 RegionSelection rs = get_regions_from_selection_and_entered ();
5503 if (!_session || rs.empty()) {
5507 bool in_command = false;
5509 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5510 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5512 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5513 XMLNode& before (alist->get_state());
5515 arv->audio_region()->set_default_envelope ();
5518 begin_reversible_command (_("reset region gain"));
5521 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5526 commit_reversible_command ();
5531 Editor::set_region_gain_visibility (RegionView* rv)
5533 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5535 arv->update_envelope_visibility();
5540 Editor::set_gain_envelope_visibility ()
5546 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5547 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5549 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5555 Editor::toggle_gain_envelope_active ()
5557 if (_ignore_region_action) {
5561 RegionSelection rs = get_regions_from_selection_and_entered ();
5563 if (!_session || rs.empty()) {
5567 bool in_command = false;
5569 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5570 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5572 arv->region()->clear_changes ();
5573 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5576 begin_reversible_command (_("region gain envelope active"));
5579 _session->add_command (new StatefulDiffCommand (arv->region()));
5584 commit_reversible_command ();
5589 Editor::toggle_region_lock ()
5591 if (_ignore_region_action) {
5595 RegionSelection rs = get_regions_from_selection_and_entered ();
5597 if (!_session || rs.empty()) {
5601 begin_reversible_command (_("toggle region lock"));
5603 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5604 (*i)->region()->clear_changes ();
5605 (*i)->region()->set_locked (!(*i)->region()->locked());
5606 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5609 commit_reversible_command ();
5613 Editor::toggle_region_video_lock ()
5615 if (_ignore_region_action) {
5619 RegionSelection rs = get_regions_from_selection_and_entered ();
5621 if (!_session || rs.empty()) {
5625 begin_reversible_command (_("Toggle Video Lock"));
5627 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5628 (*i)->region()->clear_changes ();
5629 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5630 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5633 commit_reversible_command ();
5637 Editor::toggle_region_lock_style ()
5639 if (_ignore_region_action) {
5643 RegionSelection rs = get_regions_from_selection_and_entered ();
5645 if (!_session || rs.empty()) {
5649 begin_reversible_command (_("region lock style"));
5651 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5652 (*i)->region()->clear_changes ();
5653 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5654 (*i)->region()->set_position_lock_style (ns);
5655 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5658 commit_reversible_command ();
5662 Editor::toggle_opaque_region ()
5664 if (_ignore_region_action) {
5668 RegionSelection rs = get_regions_from_selection_and_entered ();
5670 if (!_session || rs.empty()) {
5674 begin_reversible_command (_("change region opacity"));
5676 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5677 (*i)->region()->clear_changes ();
5678 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5679 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5682 commit_reversible_command ();
5686 Editor::toggle_record_enable ()
5688 bool new_state = false;
5690 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5691 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5694 if (!rtav->is_track())
5698 new_state = !rtav->track()->record_enabled();
5702 rtav->track()->set_record_enabled (new_state, this);
5707 Editor::toggle_solo ()
5709 bool new_state = false;
5711 boost::shared_ptr<RouteList> rl (new RouteList);
5713 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5714 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5721 new_state = !rtav->route()->soloed ();
5725 rl->push_back (rtav->route());
5728 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5732 Editor::toggle_mute ()
5734 bool new_state = false;
5736 boost::shared_ptr<RouteList> rl (new RouteList);
5738 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5739 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5746 new_state = !rtav->route()->muted();
5750 rl->push_back (rtav->route());
5753 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5757 Editor::toggle_solo_isolate ()
5763 Editor::fade_range ()
5765 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5767 begin_reversible_command (_("fade range"));
5769 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5770 (*i)->fade_range (selection->time);
5773 commit_reversible_command ();
5778 Editor::set_fade_length (bool in)
5780 RegionSelection rs = get_regions_from_selection_and_entered ();
5786 /* we need a region to measure the offset from the start */
5788 RegionView* rv = rs.front ();
5790 framepos_t pos = get_preferred_edit_position();
5794 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5795 /* edit point is outside the relevant region */
5800 if (pos <= rv->region()->position()) {
5804 len = pos - rv->region()->position();
5805 cmd = _("set fade in length");
5807 if (pos >= rv->region()->last_frame()) {
5811 len = rv->region()->last_frame() - pos;
5812 cmd = _("set fade out length");
5815 bool in_command = false;
5817 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5818 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5824 boost::shared_ptr<AutomationList> alist;
5826 alist = tmp->audio_region()->fade_in();
5828 alist = tmp->audio_region()->fade_out();
5831 XMLNode &before = alist->get_state();
5834 tmp->audio_region()->set_fade_in_length (len);
5835 tmp->audio_region()->set_fade_in_active (true);
5837 tmp->audio_region()->set_fade_out_length (len);
5838 tmp->audio_region()->set_fade_out_active (true);
5842 begin_reversible_command (cmd);
5845 XMLNode &after = alist->get_state();
5846 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5850 commit_reversible_command ();
5855 Editor::set_fade_in_shape (FadeShape shape)
5857 RegionSelection rs = get_regions_from_selection_and_entered ();
5862 bool in_command = false;
5864 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5865 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5871 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5872 XMLNode &before = alist->get_state();
5874 tmp->audio_region()->set_fade_in_shape (shape);
5877 begin_reversible_command (_("set fade in shape"));
5880 XMLNode &after = alist->get_state();
5881 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5885 commit_reversible_command ();
5890 Editor::set_fade_out_shape (FadeShape shape)
5892 RegionSelection rs = get_regions_from_selection_and_entered ();
5897 bool in_command = false;
5899 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5900 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5906 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5907 XMLNode &before = alist->get_state();
5909 tmp->audio_region()->set_fade_out_shape (shape);
5912 begin_reversible_command (_("set fade out shape"));
5915 XMLNode &after = alist->get_state();
5916 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5920 commit_reversible_command ();
5925 Editor::set_fade_in_active (bool yn)
5927 RegionSelection rs = get_regions_from_selection_and_entered ();
5932 bool in_command = false;
5934 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5935 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5942 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5944 ar->clear_changes ();
5945 ar->set_fade_in_active (yn);
5948 begin_reversible_command (_("set fade in active"));
5951 _session->add_command (new StatefulDiffCommand (ar));
5955 commit_reversible_command ();
5960 Editor::set_fade_out_active (bool yn)
5962 RegionSelection rs = get_regions_from_selection_and_entered ();
5967 bool in_command = false;
5969 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5970 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5976 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5978 ar->clear_changes ();
5979 ar->set_fade_out_active (yn);
5982 begin_reversible_command (_("set fade out active"));
5985 _session->add_command(new StatefulDiffCommand (ar));
5989 commit_reversible_command ();
5994 Editor::toggle_region_fades (int dir)
5996 if (_ignore_region_action) {
6000 boost::shared_ptr<AudioRegion> ar;
6003 RegionSelection rs = get_regions_from_selection_and_entered ();
6009 RegionSelection::iterator i;
6010 for (i = rs.begin(); i != rs.end(); ++i) {
6011 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6013 yn = ar->fade_out_active ();
6015 yn = ar->fade_in_active ();
6021 if (i == rs.end()) {
6025 /* XXX should this undo-able? */
6026 bool in_command = false;
6028 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6029 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6032 ar->clear_changes ();
6034 if (dir == 1 || dir == 0) {
6035 ar->set_fade_in_active (!yn);
6038 if (dir == -1 || dir == 0) {
6039 ar->set_fade_out_active (!yn);
6042 begin_reversible_command (_("toggle fade active"));
6045 _session->add_command(new StatefulDiffCommand (ar));
6049 commit_reversible_command ();
6054 /** Update region fade visibility after its configuration has been changed */
6056 Editor::update_region_fade_visibility ()
6058 bool _fade_visibility = _session->config.get_show_region_fades ();
6060 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6061 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6063 if (_fade_visibility) {
6064 v->audio_view()->show_all_fades ();
6066 v->audio_view()->hide_all_fades ();
6073 Editor::set_edit_point ()
6078 if (!mouse_frame (where, ignored)) {
6084 if (selection->markers.empty()) {
6086 mouse_add_new_marker (where);
6091 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6094 loc->move_to (where);
6100 Editor::set_playhead_cursor ()
6102 if (entered_marker) {
6103 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6108 if (!mouse_frame (where, ignored)) {
6115 _session->request_locate (where, _session->transport_rolling());
6119 if (UIConfiguration::instance().get_follow_edits()) {
6120 cancel_time_selection();
6125 Editor::split_region ()
6127 if (_drags->active ()) {
6131 //if a range is selected, separate it
6132 if ( !selection->time.empty()) {
6133 separate_regions_between (selection->time);
6137 //if no range was selected, try to find some regions to split
6138 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6140 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6142 framepos_t where = get_preferred_edit_position ();
6148 split_regions_at (where, rs);
6152 struct EditorOrderRouteSorter {
6153 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6154 return a->order_key () < b->order_key ();
6159 Editor::select_next_route()
6161 if (selection->tracks.empty()) {
6162 selection->set (track_views.front());
6166 TimeAxisView* current = selection->tracks.front();
6170 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6171 if (*i == current) {
6173 if (i != track_views.end()) {
6176 current = (*(track_views.begin()));
6177 //selection->set (*(track_views.begin()));
6182 rui = dynamic_cast<RouteUI *>(current);
6183 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6185 selection->set(current);
6187 ensure_time_axis_view_is_visible (*current, false);
6191 Editor::select_prev_route()
6193 if (selection->tracks.empty()) {
6194 selection->set (track_views.front());
6198 TimeAxisView* current = selection->tracks.front();
6202 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6203 if (*i == current) {
6205 if (i != track_views.rend()) {
6208 current = *(track_views.rbegin());
6213 rui = dynamic_cast<RouteUI *>(current);
6214 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6216 selection->set (current);
6218 ensure_time_axis_view_is_visible (*current, false);
6222 Editor::set_loop_from_selection (bool play)
6224 if (_session == 0) {
6228 framepos_t start, end;
6229 if (!get_selection_extents ( start, end))
6232 set_loop_range (start, end, _("set loop range from selection"));
6235 _session->request_play_loop (true, true);
6240 Editor::set_loop_from_region (bool play)
6242 framepos_t start, end;
6243 if (!get_selection_extents ( start, end))
6246 set_loop_range (start, end, _("set loop range from region"));
6249 _session->request_locate (start, true);
6250 _session->request_play_loop (true);
6255 Editor::set_punch_from_selection ()
6257 if (_session == 0) {
6261 framepos_t start, end;
6262 if (!get_selection_extents ( start, end))
6265 set_punch_range (start, end, _("set punch range from selection"));
6269 Editor::set_session_extents_from_selection ()
6271 if (_session == 0) {
6275 framepos_t start, end;
6276 if (!get_selection_extents ( start, end))
6280 if ((loc = _session->locations()->session_range_location()) == 0) {
6281 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6283 XMLNode &before = loc->get_state();
6285 _session->set_session_extents ( start, end );
6287 XMLNode &after = loc->get_state();
6289 begin_reversible_command (_("set session start/end from selection"));
6291 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6293 commit_reversible_command ();
6298 Editor::set_punch_start_from_edit_point ()
6302 framepos_t start = 0;
6303 framepos_t end = max_framepos;
6305 //use the existing punch end, if any
6306 Location* tpl = transport_punch_location();
6311 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6312 start = _session->audible_frame();
6314 start = get_preferred_edit_position();
6317 //snap the selection start/end
6320 //if there's not already a sensible selection endpoint, go "forever"
6321 if ( start > end ) {
6325 set_punch_range (start, end, _("set punch start from EP"));
6331 Editor::set_punch_end_from_edit_point ()
6335 framepos_t start = 0;
6336 framepos_t end = max_framepos;
6338 //use the existing punch start, if any
6339 Location* tpl = transport_punch_location();
6341 start = tpl->start();
6344 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6345 end = _session->audible_frame();
6347 end = get_preferred_edit_position();
6350 //snap the selection start/end
6353 set_punch_range (start, end, _("set punch end from EP"));
6359 Editor::set_loop_start_from_edit_point ()
6363 framepos_t start = 0;
6364 framepos_t end = max_framepos;
6366 //use the existing loop end, if any
6367 Location* tpl = transport_loop_location();
6372 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6373 start = _session->audible_frame();
6375 start = get_preferred_edit_position();
6378 //snap the selection start/end
6381 //if there's not already a sensible selection endpoint, go "forever"
6382 if ( start > end ) {
6386 set_loop_range (start, end, _("set loop start from EP"));
6392 Editor::set_loop_end_from_edit_point ()
6396 framepos_t start = 0;
6397 framepos_t end = max_framepos;
6399 //use the existing loop start, if any
6400 Location* tpl = transport_loop_location();
6402 start = tpl->start();
6405 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6406 end = _session->audible_frame();
6408 end = get_preferred_edit_position();
6411 //snap the selection start/end
6414 set_loop_range (start, end, _("set loop end from EP"));
6419 Editor::set_punch_from_region ()
6421 framepos_t start, end;
6422 if (!get_selection_extents ( start, end))
6425 set_punch_range (start, end, _("set punch range from region"));
6429 Editor::pitch_shift_region ()
6431 RegionSelection rs = get_regions_from_selection_and_entered ();
6433 RegionSelection audio_rs;
6434 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6435 if (dynamic_cast<AudioRegionView*> (*i)) {
6436 audio_rs.push_back (*i);
6440 if (audio_rs.empty()) {
6444 pitch_shift (audio_rs, 1.2);
6448 Editor::transpose_region ()
6450 RegionSelection rs = get_regions_from_selection_and_entered ();
6452 list<MidiRegionView*> midi_region_views;
6453 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6454 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6456 midi_region_views.push_back (mrv);
6461 int const r = d.run ();
6462 if (r != RESPONSE_ACCEPT) {
6466 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6467 (*i)->midi_region()->transpose (d.semitones ());
6472 Editor::set_tempo_from_region ()
6474 RegionSelection rs = get_regions_from_selection_and_entered ();
6476 if (!_session || rs.empty()) {
6480 RegionView* rv = rs.front();
6482 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6486 Editor::use_range_as_bar ()
6488 framepos_t start, end;
6489 if (get_edit_op_range (start, end)) {
6490 define_one_bar (start, end);
6495 Editor::define_one_bar (framepos_t start, framepos_t end)
6497 framepos_t length = end - start;
6499 const Meter& m (_session->tempo_map().meter_at (start));
6501 /* length = 1 bar */
6503 /* now we want frames per beat.
6504 we have frames per bar, and beats per bar, so ...
6507 /* XXXX METER MATH */
6509 double frames_per_beat = length / m.divisions_per_bar();
6511 /* beats per minute = */
6513 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6515 /* now decide whether to:
6517 (a) set global tempo
6518 (b) add a new tempo marker
6522 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6524 bool do_global = false;
6526 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6528 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6529 at the start, or create a new marker
6532 vector<string> options;
6533 options.push_back (_("Cancel"));
6534 options.push_back (_("Add new marker"));
6535 options.push_back (_("Set global tempo"));
6538 _("Define one bar"),
6539 _("Do you want to set the global tempo or add a new tempo marker?"),
6543 c.set_default_response (2);
6559 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6560 if the marker is at the region starter, change it, otherwise add
6565 begin_reversible_command (_("set tempo from region"));
6566 XMLNode& before (_session->tempo_map().get_state());
6569 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6570 } else if (t.frame() == start) {
6571 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6573 Timecode::BBT_Time bbt;
6574 _session->tempo_map().bbt_time (start, bbt);
6575 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6578 XMLNode& after (_session->tempo_map().get_state());
6580 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6581 commit_reversible_command ();
6585 Editor::split_region_at_transients ()
6587 AnalysisFeatureList positions;
6589 RegionSelection rs = get_regions_from_selection_and_entered ();
6591 if (!_session || rs.empty()) {
6595 begin_reversible_command (_("split regions"));
6597 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6599 RegionSelection::iterator tmp;
6604 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6606 if (ar && (ar->get_transients (positions) == 0)) {
6607 split_region_at_points ((*i)->region(), positions, true);
6614 commit_reversible_command ();
6619 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6621 bool use_rhythmic_rodent = false;
6623 boost::shared_ptr<Playlist> pl = r->playlist();
6625 list<boost::shared_ptr<Region> > new_regions;
6631 if (positions.empty()) {
6636 if (positions.size() > 20 && can_ferret) {
6637 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);
6638 MessageDialog msg (msgstr,
6641 Gtk::BUTTONS_OK_CANCEL);
6644 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6645 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6647 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6650 msg.set_title (_("Excessive split?"));
6653 int response = msg.run();
6659 case RESPONSE_APPLY:
6660 use_rhythmic_rodent = true;
6667 if (use_rhythmic_rodent) {
6668 show_rhythm_ferret ();
6672 AnalysisFeatureList::const_iterator x;
6674 pl->clear_changes ();
6675 pl->clear_owned_changes ();
6677 x = positions.begin();
6679 if (x == positions.end()) {
6684 pl->remove_region (r);
6688 while (x != positions.end()) {
6690 /* deal with positons that are out of scope of present region bounds */
6691 if (*x <= 0 || *x > r->length()) {
6696 /* file start = original start + how far we from the initial position ?
6699 framepos_t file_start = r->start() + pos;
6701 /* length = next position - current position
6704 framepos_t len = (*x) - pos;
6706 /* XXX we do we really want to allow even single-sample regions?
6707 shouldn't we have some kind of lower limit on region size?
6716 if (RegionFactory::region_name (new_name, r->name())) {
6720 /* do NOT announce new regions 1 by one, just wait till they are all done */
6724 plist.add (ARDOUR::Properties::start, file_start);
6725 plist.add (ARDOUR::Properties::length, len);
6726 plist.add (ARDOUR::Properties::name, new_name);
6727 plist.add (ARDOUR::Properties::layer, 0);
6729 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6730 /* because we set annouce to false, manually add the new region to the
6733 RegionFactory::map_add (nr);
6735 pl->add_region (nr, r->position() + pos);
6738 new_regions.push_front(nr);
6747 RegionFactory::region_name (new_name, r->name());
6749 /* Add the final region */
6752 plist.add (ARDOUR::Properties::start, r->start() + pos);
6753 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6754 plist.add (ARDOUR::Properties::name, new_name);
6755 plist.add (ARDOUR::Properties::layer, 0);
6757 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6758 /* because we set annouce to false, manually add the new region to the
6761 RegionFactory::map_add (nr);
6762 pl->add_region (nr, r->position() + pos);
6765 new_regions.push_front(nr);
6770 /* We might have removed regions, which alters other regions' layering_index,
6771 so we need to do a recursive diff here.
6773 vector<Command*> cmds;
6775 _session->add_commands (cmds);
6777 _session->add_command (new StatefulDiffCommand (pl));
6781 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6782 set_selected_regionview_from_region_list ((*i), Selection::Add);
6788 Editor::place_transient()
6794 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6800 framepos_t where = get_preferred_edit_position();
6802 begin_reversible_command (_("place transient"));
6804 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6805 framepos_t position = (*r)->region()->position();
6806 (*r)->region()->add_transient(where - position);
6809 commit_reversible_command ();
6813 Editor::remove_transient(ArdourCanvas::Item* item)
6819 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6822 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6823 _arv->remove_transient (*(float*) _line->get_data ("position"));
6827 Editor::snap_regions_to_grid ()
6829 list <boost::shared_ptr<Playlist > > used_playlists;
6831 RegionSelection rs = get_regions_from_selection_and_entered ();
6833 if (!_session || rs.empty()) {
6837 begin_reversible_command (_("snap regions to grid"));
6839 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6841 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6843 if (!pl->frozen()) {
6844 /* we haven't seen this playlist before */
6846 /* remember used playlists so we can thaw them later */
6847 used_playlists.push_back(pl);
6851 framepos_t start_frame = (*r)->region()->first_frame ();
6852 snap_to (start_frame);
6853 (*r)->region()->set_position (start_frame);
6856 while (used_playlists.size() > 0) {
6857 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6859 used_playlists.pop_front();
6862 commit_reversible_command ();
6866 Editor::close_region_gaps ()
6868 list <boost::shared_ptr<Playlist > > used_playlists;
6870 RegionSelection rs = get_regions_from_selection_and_entered ();
6872 if (!_session || rs.empty()) {
6876 Dialog dialog (_("Close Region Gaps"));
6879 table.set_spacings (12);
6880 table.set_border_width (12);
6881 Label* l = manage (left_aligned_label (_("Crossfade length")));
6882 table.attach (*l, 0, 1, 0, 1);
6884 SpinButton spin_crossfade (1, 0);
6885 spin_crossfade.set_range (0, 15);
6886 spin_crossfade.set_increments (1, 1);
6887 spin_crossfade.set_value (5);
6888 table.attach (spin_crossfade, 1, 2, 0, 1);
6890 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6892 l = manage (left_aligned_label (_("Pull-back length")));
6893 table.attach (*l, 0, 1, 1, 2);
6895 SpinButton spin_pullback (1, 0);
6896 spin_pullback.set_range (0, 100);
6897 spin_pullback.set_increments (1, 1);
6898 spin_pullback.set_value(30);
6899 table.attach (spin_pullback, 1, 2, 1, 2);
6901 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6903 dialog.get_vbox()->pack_start (table);
6904 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6905 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6908 if (dialog.run () == RESPONSE_CANCEL) {
6912 framepos_t crossfade_len = spin_crossfade.get_value();
6913 framepos_t pull_back_frames = spin_pullback.get_value();
6915 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6916 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6918 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6920 begin_reversible_command (_("close region gaps"));
6923 boost::shared_ptr<Region> last_region;
6925 rs.sort_by_position_and_track();
6927 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6929 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6931 if (!pl->frozen()) {
6932 /* we haven't seen this playlist before */
6934 /* remember used playlists so we can thaw them later */
6935 used_playlists.push_back(pl);
6939 framepos_t position = (*r)->region()->position();
6941 if (idx == 0 || position < last_region->position()){
6942 last_region = (*r)->region();
6947 (*r)->region()->trim_front( (position - pull_back_frames));
6948 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6950 last_region = (*r)->region();
6955 while (used_playlists.size() > 0) {
6956 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6958 used_playlists.pop_front();
6961 commit_reversible_command ();
6965 Editor::tab_to_transient (bool forward)
6967 AnalysisFeatureList positions;
6969 RegionSelection rs = get_regions_from_selection_and_entered ();
6975 framepos_t pos = _session->audible_frame ();
6977 if (!selection->tracks.empty()) {
6979 /* don't waste time searching for transients in duplicate playlists.
6982 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6984 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6986 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6989 boost::shared_ptr<Track> tr = rtv->track();
6991 boost::shared_ptr<Playlist> pl = tr->playlist ();
6993 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6996 positions.push_back (result);
7009 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7010 (*r)->region()->get_transients (positions);
7014 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7017 AnalysisFeatureList::iterator x;
7019 for (x = positions.begin(); x != positions.end(); ++x) {
7025 if (x != positions.end ()) {
7026 _session->request_locate (*x);
7030 AnalysisFeatureList::reverse_iterator x;
7032 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7038 if (x != positions.rend ()) {
7039 _session->request_locate (*x);
7045 Editor::playhead_forward_to_grid ()
7051 framepos_t pos = playhead_cursor->current_frame ();
7052 if (pos < max_framepos - 1) {
7054 snap_to_internal (pos, RoundUpAlways, false);
7055 _session->request_locate (pos);
7061 Editor::playhead_backward_to_grid ()
7067 framepos_t pos = playhead_cursor->current_frame ();
7070 snap_to_internal (pos, RoundDownAlways, false);
7071 _session->request_locate (pos);
7076 Editor::set_track_height (Height h)
7078 TrackSelection& ts (selection->tracks);
7080 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7081 (*x)->set_height_enum (h);
7086 Editor::toggle_tracks_active ()
7088 TrackSelection& ts (selection->tracks);
7090 bool target = false;
7096 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7097 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7101 target = !rtv->_route->active();
7104 rtv->_route->set_active (target, this);
7110 Editor::remove_tracks ()
7112 /* this will delete GUI objects that may be the subject of an event
7113 handler in which this method is called. Defer actual deletion to the
7114 next idle callback, when all event handling is finished.
7116 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7120 Editor::idle_remove_tracks ()
7123 return false; /* do not call again */
7127 Editor::_remove_tracks ()
7129 TrackSelection& ts (selection->tracks);
7135 vector<string> choices;
7139 const char* trackstr;
7141 vector<boost::shared_ptr<Route> > routes;
7142 bool special_bus = false;
7144 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7145 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7149 if (rtv->is_track()) {
7154 routes.push_back (rtv->_route);
7156 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7161 if (special_bus && !Config->get_allow_special_bus_removal()) {
7162 MessageDialog msg (_("That would be bad news ...."),
7166 msg.set_secondary_text (string_compose (_(
7167 "Removing the master or monitor bus is such a bad idea\n\
7168 that %1 is not going to allow it.\n\
7170 If you really want to do this sort of thing\n\
7171 edit your ardour.rc file to set the\n\
7172 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7179 if (ntracks + nbusses == 0) {
7183 trackstr = P_("track", "tracks", ntracks);
7184 busstr = P_("bus", "busses", nbusses);
7188 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\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!"),
7191 ntracks, trackstr, nbusses, busstr);
7193 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7194 "(You may also lose the playlists associated with the %2)\n\n"
7195 "This action cannot be undone, and the session file will be overwritten!"),
7198 } else if (nbusses) {
7199 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7200 "This action cannot be undone, and the session file will be overwritten"),
7204 choices.push_back (_("No, do nothing."));
7205 if (ntracks + nbusses > 1) {
7206 choices.push_back (_("Yes, remove them."));
7208 choices.push_back (_("Yes, remove it."));
7213 title = string_compose (_("Remove %1"), trackstr);
7215 title = string_compose (_("Remove %1"), busstr);
7218 Choice prompter (title, prompt, choices);
7220 if (prompter.run () != 1) {
7225 Session::StateProtector sp (_session);
7226 DisplaySuspender ds;
7227 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7228 _session->remove_route (*x);
7234 Editor::do_insert_time ()
7236 if (selection->tracks.empty()) {
7240 InsertRemoveTimeDialog d (*this);
7241 int response = d.run ();
7243 if (response != RESPONSE_OK) {
7247 if (d.distance() == 0) {
7251 InsertTimeOption opt = d.intersected_region_action ();
7254 get_preferred_edit_position(),
7260 d.move_glued_markers(),
7261 d.move_locked_markers(),
7267 Editor::insert_time (
7268 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7269 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7273 if (Config->get_edit_mode() == Lock) {
7276 bool in_command = false;
7278 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7280 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7284 /* don't operate on any playlist more than once, which could
7285 * happen if "all playlists" is enabled, but there is more
7286 * than 1 track using playlists "from" a given track.
7289 set<boost::shared_ptr<Playlist> > pl;
7291 if (all_playlists) {
7292 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7293 if (rtav && rtav->track ()) {
7294 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7295 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7300 if ((*x)->playlist ()) {
7301 pl.insert ((*x)->playlist ());
7305 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7307 (*i)->clear_changes ();
7308 (*i)->clear_owned_changes ();
7310 if (opt == SplitIntersected) {
7314 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7317 begin_reversible_command (_("insert time"));
7320 vector<Command*> cmds;
7322 _session->add_commands (cmds);
7324 _session->add_command (new StatefulDiffCommand (*i));
7328 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7331 begin_reversible_command (_("insert time"));
7334 rtav->route ()->shift (pos, frames);
7341 XMLNode& before (_session->locations()->get_state());
7342 Locations::LocationList copy (_session->locations()->list());
7344 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7346 Locations::LocationList::const_iterator tmp;
7348 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7349 bool const was_locked = (*i)->locked ();
7350 if (locked_markers_too) {
7354 if ((*i)->start() >= pos) {
7355 // move end first, in case we're moving by more than the length of the range
7356 if (!(*i)->is_mark()) {
7357 (*i)->set_end ((*i)->end() + frames);
7359 (*i)->set_start ((*i)->start() + frames);
7371 begin_reversible_command (_("insert time"));
7374 XMLNode& after (_session->locations()->get_state());
7375 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7381 begin_reversible_command (_("insert time"));
7384 XMLNode& before (_session->tempo_map().get_state());
7385 _session->tempo_map().insert_time (pos, frames);
7386 XMLNode& after (_session->tempo_map().get_state());
7387 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7391 commit_reversible_command ();
7396 Editor::do_remove_time ()
7398 if (selection->tracks.empty()) {
7402 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7403 InsertRemoveTimeDialog d (*this, true);
7405 int response = d.run ();
7407 if (response != RESPONSE_OK) {
7411 framecnt_t distance = d.distance();
7413 if (distance == 0) {
7423 d.move_glued_markers(),
7424 d.move_locked_markers(),
7430 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7431 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7433 if (Config->get_edit_mode() == Lock) {
7434 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7437 bool in_command = false;
7439 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7441 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7445 XMLNode &before = pl->get_state();
7447 std::list<AudioRange> rl;
7448 AudioRange ar(pos, pos+frames, 0);
7451 pl->shift (pos, -frames, true, ignore_music_glue);
7454 begin_reversible_command (_("cut time"));
7457 XMLNode &after = pl->get_state();
7459 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7463 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7466 begin_reversible_command (_("cut time"));
7469 rtav->route ()->shift (pos, -frames);
7473 std::list<Location*> loc_kill_list;
7478 XMLNode& before (_session->locations()->get_state());
7479 Locations::LocationList copy (_session->locations()->list());
7481 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7482 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7484 bool const was_locked = (*i)->locked ();
7485 if (locked_markers_too) {
7489 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7490 if ((*i)->end() >= pos
7491 && (*i)->end() < pos+frames
7492 && (*i)->start() >= pos
7493 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7495 loc_kill_list.push_back(*i);
7496 } else { // only start or end is included, try to do the right thing
7497 // move start before moving end, to avoid trying to move the end to before the start
7498 // if we're removing more time than the length of the range
7499 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7500 // start is within cut
7501 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7503 } else if ((*i)->start() >= pos+frames) {
7504 // start (and thus entire range) lies beyond end of cut
7505 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7508 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7509 // end is inside cut
7510 (*i)->set_end (pos); // bring the end to the cut
7512 } else if ((*i)->end() >= pos+frames) {
7513 // end is beyond end of cut
7514 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7519 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7520 loc_kill_list.push_back(*i);
7522 } else if ((*i)->start() >= pos) {
7523 (*i)->set_start ((*i)->start() -frames);
7533 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7534 _session->locations()->remove( *i );
7539 begin_reversible_command (_("cut time"));
7542 XMLNode& after (_session->locations()->get_state());
7543 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7548 XMLNode& before (_session->tempo_map().get_state());
7550 if (_session->tempo_map().remove_time (pos, frames) ) {
7552 begin_reversible_command (_("remove time"));
7555 XMLNode& after (_session->tempo_map().get_state());
7556 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7561 commit_reversible_command ();
7566 Editor::fit_selection ()
7568 if (!selection->tracks.empty()) {
7569 fit_tracks (selection->tracks);
7573 /* no selected tracks - use tracks with selected regions */
7575 if (!selection->regions.empty()) {
7576 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7577 tvl.push_back (&(*r)->get_time_axis_view ());
7583 } else if (internal_editing()) {
7584 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7587 if (entered_track) {
7588 tvl.push_back (entered_track);
7597 Editor::fit_tracks (TrackViewList & tracks)
7599 if (tracks.empty()) {
7603 uint32_t child_heights = 0;
7604 int visible_tracks = 0;
7606 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7608 if (!(*t)->marked_for_display()) {
7612 child_heights += (*t)->effective_height() - (*t)->current_height();
7616 /* compute the per-track height from:
7618 total canvas visible height -
7619 height that will be taken by visible children of selected
7620 tracks - height of the ruler/hscroll area
7622 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7623 double first_y_pos = DBL_MAX;
7625 if (h < TimeAxisView::preset_height (HeightSmall)) {
7626 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7627 /* too small to be displayed */
7631 undo_visual_stack.push_back (current_visual_state (true));
7632 PBD::Unwinder<bool> nsv (no_save_visual, true);
7634 /* build a list of all tracks, including children */
7637 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7639 TimeAxisView::Children c = (*i)->get_child_list ();
7640 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7641 all.push_back (j->get());
7646 // find selection range.
7647 // if someone knows how to user TrackViewList::iterator for this
7649 int selected_top = -1;
7650 int selected_bottom = -1;
7652 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7653 if ((*t)->marked_for_display ()) {
7654 if (tracks.contains(*t)) {
7655 if (selected_top == -1) {
7658 selected_bottom = i;
7664 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7665 if ((*t)->marked_for_display ()) {
7666 if (tracks.contains(*t)) {
7667 (*t)->set_height (h);
7668 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7670 if (i > selected_top && i < selected_bottom) {
7671 hide_track_in_display (*t);
7678 set the controls_layout height now, because waiting for its size
7679 request signal handler will cause the vertical adjustment setting to fail
7682 controls_layout.property_height () = _full_canvas_height;
7683 vertical_adjustment.set_value (first_y_pos);
7685 redo_visual_stack.push_back (current_visual_state (true));
7687 visible_tracks_selector.set_text (_("Sel"));
7691 Editor::save_visual_state (uint32_t n)
7693 while (visual_states.size() <= n) {
7694 visual_states.push_back (0);
7697 if (visual_states[n] != 0) {
7698 delete visual_states[n];
7701 visual_states[n] = current_visual_state (true);
7706 Editor::goto_visual_state (uint32_t n)
7708 if (visual_states.size() <= n) {
7712 if (visual_states[n] == 0) {
7716 use_visual_state (*visual_states[n]);
7720 Editor::start_visual_state_op (uint32_t n)
7722 save_visual_state (n);
7724 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7726 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7727 pup->set_text (buf);
7732 Editor::cancel_visual_state_op (uint32_t n)
7734 goto_visual_state (n);
7738 Editor::toggle_region_mute ()
7740 if (_ignore_region_action) {
7744 RegionSelection rs = get_regions_from_selection_and_entered ();
7750 if (rs.size() > 1) {
7751 begin_reversible_command (_("mute regions"));
7753 begin_reversible_command (_("mute region"));
7756 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7758 (*i)->region()->playlist()->clear_changes ();
7759 (*i)->region()->set_muted (!(*i)->region()->muted ());
7760 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7764 commit_reversible_command ();
7768 Editor::combine_regions ()
7770 /* foreach track with selected regions, take all selected regions
7771 and join them into a new region containing the subregions (as a
7775 typedef set<RouteTimeAxisView*> RTVS;
7778 if (selection->regions.empty()) {
7782 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7783 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7786 tracks.insert (rtv);
7790 begin_reversible_command (_("combine regions"));
7792 vector<RegionView*> new_selection;
7794 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7797 if ((rv = (*i)->combine_regions ()) != 0) {
7798 new_selection.push_back (rv);
7802 selection->clear_regions ();
7803 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7804 selection->add (*i);
7807 commit_reversible_command ();
7811 Editor::uncombine_regions ()
7813 typedef set<RouteTimeAxisView*> RTVS;
7816 if (selection->regions.empty()) {
7820 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7821 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7824 tracks.insert (rtv);
7828 begin_reversible_command (_("uncombine regions"));
7830 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7831 (*i)->uncombine_regions ();
7834 commit_reversible_command ();
7838 Editor::toggle_midi_input_active (bool flip_others)
7841 boost::shared_ptr<RouteList> rl (new RouteList);
7843 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7844 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7850 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7853 rl->push_back (rtav->route());
7854 onoff = !mt->input_active();
7858 _session->set_exclusive_input_active (rl, onoff, flip_others);
7865 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7867 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7868 lock_dialog->get_vbox()->pack_start (*padlock);
7870 ArdourButton* b = manage (new ArdourButton);
7871 b->set_name ("lock button");
7872 b->set_text (_("Click to unlock"));
7873 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7874 lock_dialog->get_vbox()->pack_start (*b);
7876 lock_dialog->get_vbox()->show_all ();
7877 lock_dialog->set_size_request (200, 200);
7880 delete _main_menu_disabler;
7881 _main_menu_disabler = new MainMenuDisabler;
7883 lock_dialog->present ();
7889 lock_dialog->hide ();
7891 delete _main_menu_disabler;
7893 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7894 start_lock_event_timing ();
7899 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7901 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7905 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7907 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7908 Gtkmm2ext::UI::instance()->flush_pending ();
7912 Editor::bring_all_sources_into_session ()
7919 ArdourDialog w (_("Moving embedded files into session folder"));
7920 w.get_vbox()->pack_start (msg);
7923 /* flush all pending GUI events because we're about to start copying
7927 Gtkmm2ext::UI::instance()->flush_pending ();
7931 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));