2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
60 #include "ardour/transpose.h"
62 #include "canvas/canvas.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_remove_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
100 #include "transpose_dialog.h"
101 #include "transform_dialog.h"
102 #include "ui_config.h"
107 using namespace ARDOUR;
110 using namespace Gtkmm2ext;
111 using namespace Editing;
112 using Gtkmm2ext::Keyboard;
114 /***********************************************************************
116 ***********************************************************************/
119 Editor::undo (uint32_t n)
121 if (_drags->active ()) {
127 if (_session->undo_depth() == 0) {
128 undo_action->set_sensitive(false);
130 redo_action->set_sensitive(true);
131 begin_selection_op_history ();
136 Editor::redo (uint32_t n)
138 if (_drags->active ()) {
144 if (_session->redo_depth() == 0) {
145 redo_action->set_sensitive(false);
147 undo_action->set_sensitive(true);
148 begin_selection_op_history ();
153 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
157 RegionSelection pre_selected_regions = selection->regions;
158 bool working_on_selection = !pre_selected_regions.empty();
160 list<boost::shared_ptr<Playlist> > used_playlists;
161 list<RouteTimeAxisView*> used_trackviews;
163 if (regions.empty()) {
167 begin_reversible_command (_("split"));
169 // if splitting a single region, and snap-to is using
170 // region boundaries, don't pay attention to them
172 if (regions.size() == 1) {
173 switch (_snap_type) {
174 case SnapToRegionStart:
175 case SnapToRegionSync:
176 case SnapToRegionEnd:
185 EditorFreeze(); /* Emit Signal */
188 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
190 RegionSelection::iterator tmp;
192 /* XXX this test needs to be more complicated, to make sure we really
193 have something to split.
196 if (!(*a)->region()->covers (where)) {
204 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
212 /* we haven't seen this playlist before */
214 /* remember used playlists so we can thaw them later */
215 used_playlists.push_back(pl);
217 TimeAxisView& tv = (*a)->get_time_axis_view();
218 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
220 used_trackviews.push_back (rtv);
227 pl->clear_changes ();
228 pl->split_region ((*a)->region(), where);
229 _session->add_command (new StatefulDiffCommand (pl));
235 latest_regionviews.clear ();
237 vector<sigc::connection> region_added_connections;
239 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
240 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
243 while (used_playlists.size() > 0) {
244 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
246 used_playlists.pop_front();
249 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
254 EditorThaw(); /* Emit Signal */
257 if (working_on_selection) {
258 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
260 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
261 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
262 /* There are three classes of regions that we might want selected after
263 splitting selected regions:
264 - regions selected before the split operation, and unaffected by it
265 - newly-created regions before the split
266 - newly-created regions after the split
269 if (rsas & Existing) {
270 // region selections that existed before the split.
271 selection->add ( pre_selected_regions );
274 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
275 if ((*ri)->region()->position() < where) {
276 // new regions created before the split
277 if (rsas & NewlyCreatedLeft) {
278 selection->add (*ri);
281 // new regions created after the split
282 if (rsas & NewlyCreatedRight) {
283 selection->add (*ri);
287 _ignore_follow_edits = false;
289 _ignore_follow_edits = true;
290 if( working_on_selection ) {
291 selection->add (latest_regionviews); //these are the new regions created after the split
293 _ignore_follow_edits = false;
296 commit_reversible_command ();
299 /** Move one extreme of the current range selection. If more than one range is selected,
300 * the start of the earliest range or the end of the latest range is moved.
302 * @param move_end true to move the end of the current range selection, false to move
304 * @param next true to move the extreme to the next region boundary, false to move to
308 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
310 if (selection->time.start() == selection->time.end_frame()) {
314 framepos_t start = selection->time.start ();
315 framepos_t end = selection->time.end_frame ();
317 /* the position of the thing we may move */
318 framepos_t pos = move_end ? end : start;
319 int dir = next ? 1 : -1;
321 /* so we don't find the current region again */
322 if (dir > 0 || pos > 0) {
326 framepos_t const target = get_region_boundary (pos, dir, true, false);
341 begin_reversible_selection_op (_("alter selection"));
342 selection->set_preserving_all_ranges (start, end);
343 commit_reversible_selection_op ();
347 Editor::nudge_forward_release (GdkEventButton* ev)
349 if (ev->state & Keyboard::PrimaryModifier) {
350 nudge_forward (false, true);
352 nudge_forward (false, false);
358 Editor::nudge_backward_release (GdkEventButton* ev)
360 if (ev->state & Keyboard::PrimaryModifier) {
361 nudge_backward (false, true);
363 nudge_backward (false, false);
370 Editor::nudge_forward (bool next, bool force_playhead)
373 framepos_t next_distance;
379 RegionSelection rs = get_regions_from_selection_and_entered ();
381 if (!force_playhead && !rs.empty()) {
383 begin_reversible_command (_("nudge regions forward"));
385 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
386 boost::shared_ptr<Region> r ((*i)->region());
388 distance = get_nudge_distance (r->position(), next_distance);
391 distance = next_distance;
395 r->set_position (r->position() + distance);
396 _session->add_command (new StatefulDiffCommand (r));
399 commit_reversible_command ();
402 } else if (!force_playhead && !selection->markers.empty()) {
405 bool in_command = false;
407 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
409 Location* loc = find_location_from_marker ((*i), is_start);
413 XMLNode& before (loc->get_state());
416 distance = get_nudge_distance (loc->start(), next_distance);
418 distance = next_distance;
420 if (max_framepos - distance > loc->start() + loc->length()) {
421 loc->set_start (loc->start() + distance);
423 loc->set_start (max_framepos - loc->length());
426 distance = get_nudge_distance (loc->end(), next_distance);
428 distance = next_distance;
430 if (max_framepos - distance > loc->end()) {
431 loc->set_end (loc->end() + distance);
433 loc->set_end (max_framepos);
437 begin_reversible_command (_("nudge location forward"));
440 XMLNode& after (loc->get_state());
441 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
446 commit_reversible_command ();
449 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
450 _session->request_locate (playhead_cursor->current_frame () + distance);
455 Editor::nudge_backward (bool next, bool force_playhead)
458 framepos_t next_distance;
464 RegionSelection rs = get_regions_from_selection_and_entered ();
466 if (!force_playhead && !rs.empty()) {
468 begin_reversible_command (_("nudge regions backward"));
470 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
471 boost::shared_ptr<Region> r ((*i)->region());
473 distance = get_nudge_distance (r->position(), next_distance);
476 distance = next_distance;
481 if (r->position() > distance) {
482 r->set_position (r->position() - distance);
486 _session->add_command (new StatefulDiffCommand (r));
489 commit_reversible_command ();
491 } else if (!force_playhead && !selection->markers.empty()) {
494 bool in_command = false;
496 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
498 Location* loc = find_location_from_marker ((*i), is_start);
502 XMLNode& before (loc->get_state());
505 distance = get_nudge_distance (loc->start(), next_distance);
507 distance = next_distance;
509 if (distance < loc->start()) {
510 loc->set_start (loc->start() - distance);
515 distance = get_nudge_distance (loc->end(), next_distance);
518 distance = next_distance;
521 if (distance < loc->end() - loc->length()) {
522 loc->set_end (loc->end() - distance);
524 loc->set_end (loc->length());
528 begin_reversible_command (_("nudge location forward"));
531 XMLNode& after (loc->get_state());
532 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
536 commit_reversible_command ();
541 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
543 if (playhead_cursor->current_frame () > distance) {
544 _session->request_locate (playhead_cursor->current_frame () - distance);
546 _session->goto_start();
552 Editor::nudge_forward_capture_offset ()
554 RegionSelection rs = get_regions_from_selection_and_entered ();
556 if (!_session || rs.empty()) {
560 begin_reversible_command (_("nudge forward"));
562 framepos_t const distance = _session->worst_output_latency();
564 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
565 boost::shared_ptr<Region> r ((*i)->region());
568 r->set_position (r->position() + distance);
569 _session->add_command(new StatefulDiffCommand (r));
572 commit_reversible_command ();
576 Editor::nudge_backward_capture_offset ()
578 RegionSelection rs = get_regions_from_selection_and_entered ();
580 if (!_session || rs.empty()) {
584 begin_reversible_command (_("nudge backward"));
586 framepos_t const distance = _session->worst_output_latency();
588 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
589 boost::shared_ptr<Region> r ((*i)->region());
593 if (r->position() > distance) {
594 r->set_position (r->position() - distance);
598 _session->add_command(new StatefulDiffCommand (r));
601 commit_reversible_command ();
604 struct RegionSelectionPositionSorter {
605 bool operator() (RegionView* a, RegionView* b) {
606 return a->region()->position() < b->region()->position();
611 Editor::sequence_regions ()
614 framepos_t r_end_prev;
622 RegionSelection rs = get_regions_from_selection_and_entered ();
623 rs.sort(RegionSelectionPositionSorter());
627 bool in_command = false;
629 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
630 boost::shared_ptr<Region> r ((*i)->region());
638 if(r->position_locked())
645 r->set_position(r_end_prev);
649 begin_reversible_command (_("sequence regions"));
652 _session->add_command (new StatefulDiffCommand (r));
654 r_end=r->position() + r->length();
660 commit_reversible_command ();
669 Editor::move_to_start ()
671 _session->goto_start ();
675 Editor::move_to_end ()
678 _session->request_locate (_session->current_end_frame());
682 Editor::build_region_boundary_cache ()
685 vector<RegionPoint> interesting_points;
686 boost::shared_ptr<Region> r;
687 TrackViewList tracks;
690 region_boundary_cache.clear ();
696 switch (_snap_type) {
697 case SnapToRegionStart:
698 interesting_points.push_back (Start);
700 case SnapToRegionEnd:
701 interesting_points.push_back (End);
703 case SnapToRegionSync:
704 interesting_points.push_back (SyncPoint);
706 case SnapToRegionBoundary:
707 interesting_points.push_back (Start);
708 interesting_points.push_back (End);
711 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
712 abort(); /*NOTREACHED*/
716 TimeAxisView *ontrack = 0;
719 if (!selection->tracks.empty()) {
720 tlist = selection->tracks.filter_to_unique_playlists ();
722 tlist = track_views.filter_to_unique_playlists ();
725 while (pos < _session->current_end_frame() && !at_end) {
728 framepos_t lpos = max_framepos;
730 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
732 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
733 if (*p == interesting_points.back()) {
736 /* move to next point type */
742 rpos = r->first_frame();
746 rpos = r->last_frame();
750 rpos = r->sync_position ();
758 RouteTimeAxisView *rtav;
760 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
761 if (rtav->track() != 0) {
762 speed = rtav->track()->speed();
766 rpos = track_frame_to_session_frame (rpos, speed);
772 /* prevent duplicates, but we don't use set<> because we want to be able
776 vector<framepos_t>::iterator ri;
778 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
784 if (ri == region_boundary_cache.end()) {
785 region_boundary_cache.push_back (rpos);
792 /* finally sort to be sure that the order is correct */
794 sort (region_boundary_cache.begin(), region_boundary_cache.end());
797 boost::shared_ptr<Region>
798 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
800 TrackViewList::iterator i;
801 framepos_t closest = max_framepos;
802 boost::shared_ptr<Region> ret;
806 framepos_t track_frame;
807 RouteTimeAxisView *rtav;
809 for (i = tracks.begin(); i != tracks.end(); ++i) {
812 boost::shared_ptr<Region> r;
815 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
816 if (rtav->track()!=0)
817 track_speed = rtav->track()->speed();
820 track_frame = session_frame_to_track_frame(frame, track_speed);
822 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
828 rpos = r->first_frame ();
832 rpos = r->last_frame ();
836 rpos = r->sync_position ();
840 // rpos is a "track frame", converting it to "_session frame"
841 rpos = track_frame_to_session_frame(rpos, track_speed);
844 distance = rpos - frame;
846 distance = frame - rpos;
849 if (distance < closest) {
861 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
863 framecnt_t distance = max_framepos;
864 framepos_t current_nearest = -1;
866 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
867 framepos_t contender;
870 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
876 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
880 d = ::llabs (pos - contender);
883 current_nearest = contender;
888 return current_nearest;
892 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
897 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
899 if (!selection->tracks.empty()) {
901 target = find_next_region_boundary (pos, dir, selection->tracks);
905 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
906 get_onscreen_tracks (tvl);
907 target = find_next_region_boundary (pos, dir, tvl);
909 target = find_next_region_boundary (pos, dir, track_views);
915 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
916 get_onscreen_tracks (tvl);
917 target = find_next_region_boundary (pos, dir, tvl);
919 target = find_next_region_boundary (pos, dir, track_views);
927 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
929 framepos_t pos = playhead_cursor->current_frame ();
936 // so we don't find the current region again..
937 if (dir > 0 || pos > 0) {
941 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
945 _session->request_locate (target);
949 Editor::cursor_to_next_region_boundary (bool with_selection)
951 cursor_to_region_boundary (with_selection, 1);
955 Editor::cursor_to_previous_region_boundary (bool with_selection)
957 cursor_to_region_boundary (with_selection, -1);
961 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
963 boost::shared_ptr<Region> r;
964 framepos_t pos = cursor->current_frame ();
970 TimeAxisView *ontrack = 0;
972 // so we don't find the current region again..
976 if (!selection->tracks.empty()) {
978 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
980 } else if (clicked_axisview) {
983 t.push_back (clicked_axisview);
985 r = find_next_region (pos, point, dir, t, &ontrack);
989 r = find_next_region (pos, point, dir, track_views, &ontrack);
998 pos = r->first_frame ();
1002 pos = r->last_frame ();
1006 pos = r->sync_position ();
1011 RouteTimeAxisView *rtav;
1013 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1014 if (rtav->track() != 0) {
1015 speed = rtav->track()->speed();
1019 pos = track_frame_to_session_frame(pos, speed);
1021 if (cursor == playhead_cursor) {
1022 _session->request_locate (pos);
1024 cursor->set_position (pos);
1029 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1031 cursor_to_region_point (cursor, point, 1);
1035 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1037 cursor_to_region_point (cursor, point, -1);
1041 Editor::cursor_to_selection_start (EditorCursor *cursor)
1045 switch (mouse_mode) {
1047 if (!selection->regions.empty()) {
1048 pos = selection->regions.start();
1053 if (!selection->time.empty()) {
1054 pos = selection->time.start ();
1062 if (cursor == playhead_cursor) {
1063 _session->request_locate (pos);
1065 cursor->set_position (pos);
1070 Editor::cursor_to_selection_end (EditorCursor *cursor)
1074 switch (mouse_mode) {
1076 if (!selection->regions.empty()) {
1077 pos = selection->regions.end_frame();
1082 if (!selection->time.empty()) {
1083 pos = selection->time.end_frame ();
1091 if (cursor == playhead_cursor) {
1092 _session->request_locate (pos);
1094 cursor->set_position (pos);
1099 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1109 if (selection->markers.empty()) {
1113 if (!mouse_frame (mouse, ignored)) {
1117 add_location_mark (mouse);
1120 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1124 framepos_t pos = loc->start();
1126 // so we don't find the current region again..
1127 if (dir > 0 || pos > 0) {
1131 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1135 loc->move_to (target);
1139 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1141 selected_marker_to_region_boundary (with_selection, 1);
1145 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1147 selected_marker_to_region_boundary (with_selection, -1);
1151 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1153 boost::shared_ptr<Region> r;
1158 if (!_session || selection->markers.empty()) {
1162 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1166 TimeAxisView *ontrack = 0;
1170 // so we don't find the current region again..
1174 if (!selection->tracks.empty()) {
1176 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1180 r = find_next_region (pos, point, dir, track_views, &ontrack);
1189 pos = r->first_frame ();
1193 pos = r->last_frame ();
1197 pos = r->adjust_to_sync (r->first_frame());
1202 RouteTimeAxisView *rtav;
1204 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1205 if (rtav->track() != 0) {
1206 speed = rtav->track()->speed();
1210 pos = track_frame_to_session_frame(pos, speed);
1216 Editor::selected_marker_to_next_region_point (RegionPoint point)
1218 selected_marker_to_region_point (point, 1);
1222 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1224 selected_marker_to_region_point (point, -1);
1228 Editor::selected_marker_to_selection_start ()
1234 if (!_session || selection->markers.empty()) {
1238 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1242 switch (mouse_mode) {
1244 if (!selection->regions.empty()) {
1245 pos = selection->regions.start();
1250 if (!selection->time.empty()) {
1251 pos = selection->time.start ();
1263 Editor::selected_marker_to_selection_end ()
1269 if (!_session || selection->markers.empty()) {
1273 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1277 switch (mouse_mode) {
1279 if (!selection->regions.empty()) {
1280 pos = selection->regions.end_frame();
1285 if (!selection->time.empty()) {
1286 pos = selection->time.end_frame ();
1298 Editor::scroll_playhead (bool forward)
1300 framepos_t pos = playhead_cursor->current_frame ();
1301 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1304 if (pos == max_framepos) {
1308 if (pos < max_framepos - delta) {
1327 _session->request_locate (pos);
1331 Editor::cursor_align (bool playhead_to_edit)
1337 if (playhead_to_edit) {
1339 if (selection->markers.empty()) {
1343 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1346 /* move selected markers to playhead */
1348 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1351 Location* loc = find_location_from_marker (*i, ignored);
1353 if (loc->is_mark()) {
1354 loc->set_start (playhead_cursor->current_frame ());
1356 loc->set (playhead_cursor->current_frame (),
1357 playhead_cursor->current_frame () + loc->length());
1364 Editor::scroll_backward (float pages)
1366 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1367 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1370 if (leftmost_frame < cnt) {
1373 frame = leftmost_frame - cnt;
1376 reset_x_origin (frame);
1380 Editor::scroll_forward (float pages)
1382 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1383 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1386 if (max_framepos - cnt < leftmost_frame) {
1387 frame = max_framepos - cnt;
1389 frame = leftmost_frame + cnt;
1392 reset_x_origin (frame);
1396 Editor::scroll_tracks_down ()
1398 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1399 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1400 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1403 vertical_adjustment.set_value (vert_value);
1407 Editor::scroll_tracks_up ()
1409 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1413 Editor::scroll_tracks_down_line ()
1415 double vert_value = vertical_adjustment.get_value() + 60;
1417 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1418 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1421 vertical_adjustment.set_value (vert_value);
1425 Editor::scroll_tracks_up_line ()
1427 reset_y_origin (vertical_adjustment.get_value() - 60);
1431 Editor::scroll_down_one_track (bool skip_child_views)
1433 TrackViewList::reverse_iterator next = track_views.rend();
1434 const double top_of_trackviews = vertical_adjustment.get_value();
1436 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1437 if ((*t)->hidden()) {
1441 /* If this is the upper-most visible trackview, we want to display
1442 * the one above it (next)
1444 * Note that covers_y_position() is recursive and includes child views
1446 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1449 if (skip_child_views) {
1452 /* automation lane (one level, non-recursive)
1454 * - if no automation lane exists -> move to next tack
1455 * - if the first (here: bottom-most) matches -> move to next tack
1456 * - if no y-axis match is found -> the current track is at the top
1457 * -> move to last (here: top-most) automation lane
1459 TimeAxisView::Children kids = (*t)->get_child_list();
1460 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1462 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1463 if ((*ci)->hidden()) {
1467 std::pair<TimeAxisView*,double> dev;
1468 dev = (*ci)->covers_y_position (top_of_trackviews);
1470 /* some automation lane is currently at the top */
1471 if (ci == kids.rbegin()) {
1472 /* first (bottom-most) autmation lane is at the top.
1473 * -> move to next track
1482 if (nkid != kids.rend()) {
1483 ensure_time_axis_view_is_visible (**nkid, true);
1491 /* move to the track below the first one that covers the */
1493 if (next != track_views.rend()) {
1494 ensure_time_axis_view_is_visible (**next, true);
1502 Editor::scroll_up_one_track (bool skip_child_views)
1504 TrackViewList::iterator prev = track_views.end();
1505 double top_of_trackviews = vertical_adjustment.get_value ();
1507 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1509 if ((*t)->hidden()) {
1513 /* find the trackview at the top of the trackview group
1515 * Note that covers_y_position() is recursive and includes child views
1517 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1520 if (skip_child_views) {
1523 /* automation lane (one level, non-recursive)
1525 * - if no automation lane exists -> move to prev tack
1526 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1527 * (actually last automation lane of previous track, see below)
1528 * - if first (top-most) lane is at the top -> move to this track
1529 * - else move up one lane
1531 TimeAxisView::Children kids = (*t)->get_child_list();
1532 TimeAxisView::Children::iterator pkid = kids.end();
1534 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1535 if ((*ci)->hidden()) {
1539 std::pair<TimeAxisView*,double> dev;
1540 dev = (*ci)->covers_y_position (top_of_trackviews);
1542 /* some automation lane is currently at the top */
1543 if (ci == kids.begin()) {
1544 /* first (top-most) autmation lane is at the top.
1545 * jump directly to this track's top
1547 ensure_time_axis_view_is_visible (**t, true);
1550 else if (pkid != kids.end()) {
1551 /* some other automation lane is at the top.
1552 * move up to prev automation lane.
1554 ensure_time_axis_view_is_visible (**pkid, true);
1557 assert(0); // not reached
1568 if (prev != track_views.end()) {
1569 // move to bottom-most automation-lane of the previous track
1570 TimeAxisView::Children kids = (*prev)->get_child_list();
1571 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1572 if (!skip_child_views) {
1573 // find the last visible lane
1574 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1575 if (!(*ci)->hidden()) {
1581 if (pkid != kids.rend()) {
1582 ensure_time_axis_view_is_visible (**pkid, true);
1584 ensure_time_axis_view_is_visible (**prev, true);
1595 Editor::tav_zoom_step (bool coarser)
1597 DisplaySuspender ds;
1601 if (selection->tracks.empty()) {
1604 ts = &selection->tracks;
1607 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1608 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1609 tv->step_height (coarser);
1614 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1616 DisplaySuspender ds;
1620 if (selection->tracks.empty() || force_all) {
1623 ts = &selection->tracks;
1626 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1627 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1628 uint32_t h = tv->current_height ();
1633 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1638 tv->set_height (h + 5);
1645 Editor::temporal_zoom_step (bool coarser)
1647 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1649 framecnt_t nspp = samples_per_pixel;
1657 temporal_zoom (nspp);
1661 Editor::temporal_zoom (framecnt_t fpp)
1667 framepos_t current_page = current_page_samples();
1668 framepos_t current_leftmost = leftmost_frame;
1669 framepos_t current_rightmost;
1670 framepos_t current_center;
1671 framepos_t new_page_size;
1672 framepos_t half_page_size;
1673 framepos_t leftmost_after_zoom = 0;
1675 bool in_track_canvas;
1679 if (fpp == samples_per_pixel) {
1683 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1684 // segfaults for lack of memory. If somebody decides this is not high enough I
1685 // believe it can be raisen to higher values but some limit must be in place.
1687 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1688 // all of which is used for the editor track displays. The whole day
1689 // would be 4147200000 samples, so 2592000 samples per pixel.
1691 nfpp = min (fpp, (framecnt_t) 2592000);
1692 nfpp = max ((framecnt_t) 1, nfpp);
1694 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1695 half_page_size = new_page_size / 2;
1697 switch (zoom_focus) {
1699 leftmost_after_zoom = current_leftmost;
1702 case ZoomFocusRight:
1703 current_rightmost = leftmost_frame + current_page;
1704 if (current_rightmost < new_page_size) {
1705 leftmost_after_zoom = 0;
1707 leftmost_after_zoom = current_rightmost - new_page_size;
1711 case ZoomFocusCenter:
1712 current_center = current_leftmost + (current_page/2);
1713 if (current_center < half_page_size) {
1714 leftmost_after_zoom = 0;
1716 leftmost_after_zoom = current_center - half_page_size;
1720 case ZoomFocusPlayhead:
1721 /* centre playhead */
1722 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1725 leftmost_after_zoom = 0;
1726 } else if (l > max_framepos) {
1727 leftmost_after_zoom = max_framepos - new_page_size;
1729 leftmost_after_zoom = (framepos_t) l;
1733 case ZoomFocusMouse:
1734 /* try to keep the mouse over the same point in the display */
1736 if (!mouse_frame (where, in_track_canvas)) {
1737 /* use playhead instead */
1738 where = playhead_cursor->current_frame ();
1740 if (where < half_page_size) {
1741 leftmost_after_zoom = 0;
1743 leftmost_after_zoom = where - half_page_size;
1748 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1751 leftmost_after_zoom = 0;
1752 } else if (l > max_framepos) {
1753 leftmost_after_zoom = max_framepos - new_page_size;
1755 leftmost_after_zoom = (framepos_t) l;
1762 /* try to keep the edit point in the same place */
1763 where = get_preferred_edit_position ();
1767 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1770 leftmost_after_zoom = 0;
1771 } else if (l > max_framepos) {
1772 leftmost_after_zoom = max_framepos - new_page_size;
1774 leftmost_after_zoom = (framepos_t) l;
1778 /* edit point not defined */
1785 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1787 reposition_and_zoom (leftmost_after_zoom, nfpp);
1791 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1793 /* this func helps make sure we leave a little space
1794 at each end of the editor so that the zoom doesn't fit the region
1795 precisely to the screen.
1798 GdkScreen* screen = gdk_screen_get_default ();
1799 const gint pixwidth = gdk_screen_get_width (screen);
1800 const gint mmwidth = gdk_screen_get_width_mm (screen);
1801 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1802 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1804 const framepos_t range = end - start;
1805 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1806 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1808 if (start > extra_samples) {
1809 start -= extra_samples;
1814 if (max_framepos - extra_samples > end) {
1815 end += extra_samples;
1822 Editor::temporal_zoom_region (bool both_axes)
1824 framepos_t start = max_framepos;
1826 set<TimeAxisView*> tracks;
1828 if ( !get_selection_extents(start, end) )
1831 calc_extra_zoom_edges (start, end);
1833 /* if we're zooming on both axes we need to save track heights etc.
1836 undo_visual_stack.push_back (current_visual_state (both_axes));
1838 PBD::Unwinder<bool> nsv (no_save_visual, true);
1840 temporal_zoom_by_frame (start, end);
1843 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1845 /* set visible track heights appropriately */
1847 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1848 (*t)->set_height (per_track_height);
1851 /* hide irrelevant tracks */
1853 DisplaySuspender ds;
1855 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1856 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1857 hide_track_in_display (*i);
1861 vertical_adjustment.set_value (0.0);
1864 redo_visual_stack.push_back (current_visual_state (both_axes));
1869 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1871 start = max_framepos;
1875 //ToDo: if notes are selected, set extents to that selection
1877 //ToDo: if control points are selected, set extents to that selection
1879 if ( !selection->regions.empty() ) {
1880 RegionSelection rs = get_regions_from_selection_and_entered ();
1882 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1884 if ((*i)->region()->position() < start) {
1885 start = (*i)->region()->position();
1888 if ((*i)->region()->last_frame() + 1 > end) {
1889 end = (*i)->region()->last_frame() + 1;
1893 } else if (!selection->time.empty()) {
1894 start = selection->time.start();
1895 end = selection->time.end_frame();
1897 ret = false; //no selection found
1900 if ((start == 0 && end == 0) || end < start) {
1909 Editor::temporal_zoom_selection (bool both_axes)
1911 if (!selection) return;
1913 //ToDo: if notes are selected, zoom to that
1915 //ToDo: if control points are selected, zoom to that
1917 //if region(s) are selected, zoom to that
1918 if ( !selection->regions.empty() )
1919 temporal_zoom_region (both_axes);
1921 //if a range is selected, zoom to that
1922 if (!selection->time.empty()) {
1924 framepos_t start, end;
1925 if (get_selection_extents (start, end)) {
1926 calc_extra_zoom_edges(start, end);
1927 temporal_zoom_by_frame (start, end);
1937 Editor::temporal_zoom_session ()
1939 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1942 framecnt_t start = _session->current_start_frame();
1943 framecnt_t end = _session->current_end_frame();
1945 if (_session->actively_recording () ) {
1946 framepos_t cur = playhead_cursor->current_frame ();
1948 /* recording beyond the end marker; zoom out
1949 * by 5 seconds more so that if 'follow
1950 * playhead' is active we don't immediately
1953 end = cur + _session->frame_rate() * 5;
1957 if ((start == 0 && end == 0) || end < start) {
1961 calc_extra_zoom_edges(start, end);
1963 temporal_zoom_by_frame (start, end);
1968 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1970 if (!_session) return;
1972 if ((start == 0 && end == 0) || end < start) {
1976 framepos_t range = end - start;
1978 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1980 framepos_t new_page = range;
1981 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1982 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1984 if (new_leftmost > middle) {
1988 if (new_leftmost < 0) {
1992 reposition_and_zoom (new_leftmost, new_fpp);
1996 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2002 framecnt_t range_before = frame - leftmost_frame;
2006 if (samples_per_pixel <= 1) {
2009 new_spp = samples_per_pixel + (samples_per_pixel/2);
2011 range_before += range_before/2;
2013 if (samples_per_pixel >= 1) {
2014 new_spp = samples_per_pixel - (samples_per_pixel/2);
2016 /* could bail out here since we cannot zoom any finer,
2017 but leave that to the equality test below
2019 new_spp = samples_per_pixel;
2022 range_before -= range_before/2;
2025 if (new_spp == samples_per_pixel) {
2029 /* zoom focus is automatically taken as @param frame when this
2033 framepos_t new_leftmost = frame - (framepos_t)range_before;
2035 if (new_leftmost > frame) {
2039 if (new_leftmost < 0) {
2043 reposition_and_zoom (new_leftmost, new_spp);
2048 Editor::choose_new_marker_name(string &name) {
2050 if (!UIConfiguration::instance().get_name_new_markers()) {
2051 /* don't prompt user for a new name */
2055 ArdourPrompter dialog (true);
2057 dialog.set_prompt (_("New Name:"));
2059 dialog.set_title (_("New Location Marker"));
2061 dialog.set_name ("MarkNameWindow");
2062 dialog.set_size_request (250, -1);
2063 dialog.set_position (Gtk::WIN_POS_MOUSE);
2065 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2066 dialog.set_initial_text (name);
2070 switch (dialog.run ()) {
2071 case RESPONSE_ACCEPT:
2077 dialog.get_result(name);
2084 Editor::add_location_from_selection ()
2088 if (selection->time.empty()) {
2092 if (_session == 0 || clicked_axisview == 0) {
2096 framepos_t start = selection->time[clicked_selection].start;
2097 framepos_t end = selection->time[clicked_selection].end;
2099 _session->locations()->next_available_name(rangename,"selection");
2100 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2102 begin_reversible_command (_("add marker"));
2104 XMLNode &before = _session->locations()->get_state();
2105 _session->locations()->add (location, true);
2106 XMLNode &after = _session->locations()->get_state();
2107 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2109 commit_reversible_command ();
2113 Editor::add_location_mark (framepos_t where)
2117 select_new_marker = true;
2119 _session->locations()->next_available_name(markername,"mark");
2120 if (!choose_new_marker_name(markername)) {
2123 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2124 begin_reversible_command (_("add marker"));
2126 XMLNode &before = _session->locations()->get_state();
2127 _session->locations()->add (location, true);
2128 XMLNode &after = _session->locations()->get_state();
2129 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2131 commit_reversible_command ();
2135 Editor::set_session_start_from_playhead ()
2141 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2142 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2144 XMLNode &before = loc->get_state();
2146 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2148 XMLNode &after = loc->get_state();
2150 begin_reversible_command (_("Set session start"));
2152 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2154 commit_reversible_command ();
2159 Editor::set_session_end_from_playhead ()
2165 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2166 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2168 XMLNode &before = loc->get_state();
2170 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2172 XMLNode &after = loc->get_state();
2174 begin_reversible_command (_("Set session start"));
2176 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2178 commit_reversible_command ();
2183 Editor::add_location_from_playhead_cursor ()
2185 add_location_mark (_session->audible_frame());
2189 Editor::remove_location_at_playhead_cursor ()
2193 XMLNode &before = _session->locations()->get_state();
2194 bool removed = false;
2196 //find location(s) at this time
2197 Locations::LocationList locs;
2198 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2199 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2200 if ((*i)->is_mark()) {
2201 _session->locations()->remove (*i);
2208 begin_reversible_command (_("remove marker"));
2209 XMLNode &after = _session->locations()->get_state();
2210 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2211 commit_reversible_command ();
2216 /** Add a range marker around each selected region */
2218 Editor::add_locations_from_region ()
2220 RegionSelection rs = get_regions_from_selection_and_entered ();
2225 bool commit = false;
2227 XMLNode &before = _session->locations()->get_state();
2229 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2231 boost::shared_ptr<Region> region = (*i)->region ();
2233 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2235 _session->locations()->add (location, true);
2240 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2241 XMLNode &after = _session->locations()->get_state();
2242 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2243 commit_reversible_command ();
2247 /** Add a single range marker around all selected regions */
2249 Editor::add_location_from_region ()
2251 RegionSelection rs = get_regions_from_selection_and_entered ();
2257 XMLNode &before = _session->locations()->get_state();
2261 if (rs.size() > 1) {
2262 _session->locations()->next_available_name(markername, "regions");
2264 RegionView* rv = *(rs.begin());
2265 boost::shared_ptr<Region> region = rv->region();
2266 markername = region->name();
2269 if (!choose_new_marker_name(markername)) {
2273 // single range spanning all selected
2274 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2275 _session->locations()->add (location, true);
2277 begin_reversible_command (_("add marker"));
2278 XMLNode &after = _session->locations()->get_state();
2279 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2280 commit_reversible_command ();
2286 Editor::jump_forward_to_mark ()
2292 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2298 _session->request_locate (pos, _session->transport_rolling());
2302 Editor::jump_backward_to_mark ()
2308 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2314 _session->request_locate (pos, _session->transport_rolling());
2320 framepos_t const pos = _session->audible_frame ();
2323 _session->locations()->next_available_name (markername, "mark");
2325 if (!choose_new_marker_name (markername)) {
2329 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2333 Editor::clear_markers ()
2336 begin_reversible_command (_("clear markers"));
2338 XMLNode &before = _session->locations()->get_state();
2339 _session->locations()->clear_markers ();
2340 XMLNode &after = _session->locations()->get_state();
2341 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2343 commit_reversible_command ();
2348 Editor::clear_ranges ()
2351 begin_reversible_command (_("clear ranges"));
2353 XMLNode &before = _session->locations()->get_state();
2355 _session->locations()->clear_ranges ();
2357 XMLNode &after = _session->locations()->get_state();
2358 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2360 commit_reversible_command ();
2365 Editor::clear_locations ()
2367 begin_reversible_command (_("clear locations"));
2369 XMLNode &before = _session->locations()->get_state();
2370 _session->locations()->clear ();
2371 XMLNode &after = _session->locations()->get_state();
2372 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2374 commit_reversible_command ();
2378 Editor::unhide_markers ()
2380 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2381 Location *l = (*i).first;
2382 if (l->is_hidden() && l->is_mark()) {
2383 l->set_hidden(false, this);
2389 Editor::unhide_ranges ()
2391 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2392 Location *l = (*i).first;
2393 if (l->is_hidden() && l->is_range_marker()) {
2394 l->set_hidden(false, this);
2399 /* INSERT/REPLACE */
2402 Editor::insert_region_list_selection (float times)
2404 RouteTimeAxisView *tv = 0;
2405 boost::shared_ptr<Playlist> playlist;
2407 if (clicked_routeview != 0) {
2408 tv = clicked_routeview;
2409 } else if (!selection->tracks.empty()) {
2410 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2413 } else if (entered_track != 0) {
2414 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2421 if ((playlist = tv->playlist()) == 0) {
2425 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2430 begin_reversible_command (_("insert region"));
2431 playlist->clear_changes ();
2432 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2433 if (Config->get_edit_mode() == Ripple)
2434 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2436 _session->add_command(new StatefulDiffCommand (playlist));
2437 commit_reversible_command ();
2440 /* BUILT-IN EFFECTS */
2443 Editor::reverse_selection ()
2448 /* GAIN ENVELOPE EDITING */
2451 Editor::edit_envelope ()
2458 Editor::transition_to_rolling (bool fwd)
2464 if (_session->config.get_external_sync()) {
2465 switch (Config->get_sync_source()) {
2469 /* transport controlled by the master */
2474 if (_session->is_auditioning()) {
2475 _session->cancel_audition ();
2479 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2483 Editor::play_from_start ()
2485 _session->request_locate (_session->current_start_frame(), true);
2489 Editor::play_from_edit_point ()
2491 _session->request_locate (get_preferred_edit_position(), true);
2495 Editor::play_from_edit_point_and_return ()
2497 framepos_t start_frame;
2498 framepos_t return_frame;
2500 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2502 if (_session->transport_rolling()) {
2503 _session->request_locate (start_frame, false);
2507 /* don't reset the return frame if its already set */
2509 if ((return_frame = _session->requested_return_frame()) < 0) {
2510 return_frame = _session->audible_frame();
2513 if (start_frame >= 0) {
2514 _session->request_roll_at_and_return (start_frame, return_frame);
2519 Editor::play_selection ()
2521 framepos_t start, end;
2522 if (!get_selection_extents ( start, end))
2525 AudioRange ar (start, end, 0);
2526 list<AudioRange> lar;
2529 _session->request_play_range (&lar, true);
2533 Editor::get_preroll ()
2535 return Config->get_preroll_seconds() * _session->frame_rate();
2540 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2542 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2545 location -= get_preroll();
2547 //don't try to locate before the beginning of time
2551 //if follow_playhead is on, keep the playhead on the screen
2552 if ( _follow_playhead )
2553 if ( location < leftmost_frame )
2554 location = leftmost_frame;
2556 _session->request_locate( location );
2560 Editor::play_with_preroll ()
2563 framepos_t preroll = get_preroll();
2565 framepos_t start, end;
2566 if (!get_selection_extents ( start, end))
2569 if (start > preroll)
2570 start = start - preroll;
2572 end = end + preroll; //"post-roll"
2574 AudioRange ar (start, end, 0);
2575 list<AudioRange> lar;
2578 _session->request_play_range (&lar, true);
2583 Editor::play_location (Location& location)
2585 if (location.start() <= location.end()) {
2589 _session->request_bounded_roll (location.start(), location.end());
2593 Editor::loop_location (Location& location)
2595 if (location.start() <= location.end()) {
2601 if ((tll = transport_loop_location()) != 0) {
2602 tll->set (location.start(), location.end());
2604 // enable looping, reposition and start rolling
2605 _session->request_locate (tll->start(), true);
2606 _session->request_play_loop (true);
2611 Editor::do_layer_operation (LayerOperation op)
2613 if (selection->regions.empty ()) {
2617 bool const multiple = selection->regions.size() > 1;
2621 begin_reversible_command (_("raise regions"));
2623 begin_reversible_command (_("raise region"));
2629 begin_reversible_command (_("raise regions to top"));
2631 begin_reversible_command (_("raise region to top"));
2637 begin_reversible_command (_("lower regions"));
2639 begin_reversible_command (_("lower region"));
2645 begin_reversible_command (_("lower regions to bottom"));
2647 begin_reversible_command (_("lower region"));
2652 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2653 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2654 (*i)->clear_owned_changes ();
2657 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2658 boost::shared_ptr<Region> r = (*i)->region ();
2670 r->lower_to_bottom ();
2674 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2675 vector<Command*> cmds;
2677 _session->add_commands (cmds);
2680 commit_reversible_command ();
2684 Editor::raise_region ()
2686 do_layer_operation (Raise);
2690 Editor::raise_region_to_top ()
2692 do_layer_operation (RaiseToTop);
2696 Editor::lower_region ()
2698 do_layer_operation (Lower);
2702 Editor::lower_region_to_bottom ()
2704 do_layer_operation (LowerToBottom);
2707 /** Show the region editor for the selected regions */
2709 Editor::show_region_properties ()
2711 selection->foreach_regionview (&RegionView::show_region_editor);
2714 /** Show the midi list editor for the selected MIDI regions */
2716 Editor::show_midi_list_editor ()
2718 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2722 Editor::rename_region ()
2724 RegionSelection rs = get_regions_from_selection_and_entered ();
2730 ArdourDialog d (*this, _("Rename Region"), true, false);
2732 Label label (_("New name:"));
2735 hbox.set_spacing (6);
2736 hbox.pack_start (label, false, false);
2737 hbox.pack_start (entry, true, true);
2739 d.get_vbox()->set_border_width (12);
2740 d.get_vbox()->pack_start (hbox, false, false);
2742 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2743 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2745 d.set_size_request (300, -1);
2747 entry.set_text (rs.front()->region()->name());
2748 entry.select_region (0, -1);
2750 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2756 int const ret = d.run();
2760 if (ret != RESPONSE_OK) {
2764 std::string str = entry.get_text();
2765 strip_whitespace_edges (str);
2767 rs.front()->region()->set_name (str);
2768 _regions->redisplay ();
2772 /** Start an audition of the first selected region */
2774 Editor::play_edit_range ()
2776 framepos_t start, end;
2778 if (get_edit_op_range (start, end)) {
2779 _session->request_bounded_roll (start, end);
2784 Editor::play_selected_region ()
2786 framepos_t start = max_framepos;
2789 RegionSelection rs = get_regions_from_selection_and_entered ();
2795 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2796 if ((*i)->region()->position() < start) {
2797 start = (*i)->region()->position();
2799 if ((*i)->region()->last_frame() + 1 > end) {
2800 end = (*i)->region()->last_frame() + 1;
2804 _session->request_bounded_roll (start, end);
2808 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2810 _session->audition_region (region);
2814 Editor::region_from_selection ()
2816 if (clicked_axisview == 0) {
2820 if (selection->time.empty()) {
2824 framepos_t start = selection->time[clicked_selection].start;
2825 framepos_t end = selection->time[clicked_selection].end;
2827 TrackViewList tracks = get_tracks_for_range_action ();
2829 framepos_t selection_cnt = end - start + 1;
2831 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2832 boost::shared_ptr<Region> current;
2833 boost::shared_ptr<Playlist> pl;
2834 framepos_t internal_start;
2837 if ((pl = (*i)->playlist()) == 0) {
2841 if ((current = pl->top_region_at (start)) == 0) {
2845 internal_start = start - current->position();
2846 RegionFactory::region_name (new_name, current->name(), true);
2850 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2851 plist.add (ARDOUR::Properties::length, selection_cnt);
2852 plist.add (ARDOUR::Properties::name, new_name);
2853 plist.add (ARDOUR::Properties::layer, 0);
2855 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2860 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2862 if (selection->time.empty() || selection->tracks.empty()) {
2866 framepos_t start, end;
2867 if (clicked_selection) {
2868 start = selection->time[clicked_selection].start;
2869 end = selection->time[clicked_selection].end;
2871 start = selection->time.start();
2872 end = selection->time.end_frame();
2875 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2876 sort_track_selection (ts);
2878 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2879 boost::shared_ptr<Region> current;
2880 boost::shared_ptr<Playlist> playlist;
2881 framepos_t internal_start;
2884 if ((playlist = (*i)->playlist()) == 0) {
2888 if ((current = playlist->top_region_at(start)) == 0) {
2892 internal_start = start - current->position();
2893 RegionFactory::region_name (new_name, current->name(), true);
2897 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2898 plist.add (ARDOUR::Properties::length, end - start + 1);
2899 plist.add (ARDOUR::Properties::name, new_name);
2901 new_regions.push_back (RegionFactory::create (current, plist));
2906 Editor::split_multichannel_region ()
2908 RegionSelection rs = get_regions_from_selection_and_entered ();
2914 vector< boost::shared_ptr<Region> > v;
2916 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2917 (*x)->region()->separate_by_channel (*_session, v);
2922 Editor::new_region_from_selection ()
2924 region_from_selection ();
2925 cancel_selection ();
2929 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2931 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2932 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2933 case Evoral::OverlapNone:
2941 * - selected tracks, or if there are none...
2942 * - tracks containing selected regions, or if there are none...
2947 Editor::get_tracks_for_range_action () const
2951 if (selection->tracks.empty()) {
2953 /* use tracks with selected regions */
2955 RegionSelection rs = selection->regions;
2957 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2958 TimeAxisView* tv = &(*i)->get_time_axis_view();
2960 if (!t.contains (tv)) {
2966 /* no regions and no tracks: use all tracks */
2972 t = selection->tracks;
2975 return t.filter_to_unique_playlists();
2979 Editor::separate_regions_between (const TimeSelection& ts)
2981 bool in_command = false;
2982 boost::shared_ptr<Playlist> playlist;
2983 RegionSelection new_selection;
2985 TrackViewList tmptracks = get_tracks_for_range_action ();
2986 sort_track_selection (tmptracks);
2988 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2990 RouteTimeAxisView* rtv;
2992 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2994 if (rtv->is_track()) {
2996 /* no edits to destructive tracks */
2998 if (rtv->track()->destructive()) {
3002 if ((playlist = rtv->playlist()) != 0) {
3004 playlist->clear_changes ();
3006 /* XXX need to consider musical time selections here at some point */
3008 double speed = rtv->track()->speed();
3011 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3013 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3014 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3016 latest_regionviews.clear ();
3018 playlist->partition ((framepos_t)((*t).start * speed),
3019 (framepos_t)((*t).end * speed), false);
3023 if (!latest_regionviews.empty()) {
3025 rtv->view()->foreach_regionview (sigc::bind (
3026 sigc::ptr_fun (add_if_covered),
3027 &(*t), &new_selection));
3030 begin_reversible_command (_("separate"));
3034 /* pick up changes to existing regions */
3036 vector<Command*> cmds;
3037 playlist->rdiff (cmds);
3038 _session->add_commands (cmds);
3040 /* pick up changes to the playlist itself (adds/removes)
3043 _session->add_command(new StatefulDiffCommand (playlist));
3052 // selection->set (new_selection);
3054 commit_reversible_command ();
3058 struct PlaylistState {
3059 boost::shared_ptr<Playlist> playlist;
3063 /** Take tracks from get_tracks_for_range_action and cut any regions
3064 * on those tracks so that the tracks are empty over the time
3068 Editor::separate_region_from_selection ()
3070 /* preferentially use *all* ranges in the time selection if we're in range mode
3071 to allow discontiguous operation, since get_edit_op_range() currently
3072 returns a single range.
3075 if (!selection->time.empty()) {
3077 separate_regions_between (selection->time);
3084 if (get_edit_op_range (start, end)) {
3086 AudioRange ar (start, end, 1);
3090 separate_regions_between (ts);
3096 Editor::separate_region_from_punch ()
3098 Location* loc = _session->locations()->auto_punch_location();
3100 separate_regions_using_location (*loc);
3105 Editor::separate_region_from_loop ()
3107 Location* loc = _session->locations()->auto_loop_location();
3109 separate_regions_using_location (*loc);
3114 Editor::separate_regions_using_location (Location& loc)
3116 if (loc.is_mark()) {
3120 AudioRange ar (loc.start(), loc.end(), 1);
3125 separate_regions_between (ts);
3128 /** Separate regions under the selected region */
3130 Editor::separate_under_selected_regions ()
3132 vector<PlaylistState> playlists;
3136 rs = get_regions_from_selection_and_entered();
3138 if (!_session || rs.empty()) {
3142 begin_reversible_command (_("separate region under"));
3144 list<boost::shared_ptr<Region> > regions_to_remove;
3146 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3147 // we can't just remove the region(s) in this loop because
3148 // this removes them from the RegionSelection, and they thus
3149 // disappear from underneath the iterator, and the ++i above
3150 // SEGVs in a puzzling fashion.
3152 // so, first iterate over the regions to be removed from rs and
3153 // add them to the regions_to_remove list, and then
3154 // iterate over the list to actually remove them.
3156 regions_to_remove.push_back ((*i)->region());
3159 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3161 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3164 // is this check necessary?
3168 vector<PlaylistState>::iterator i;
3170 //only take state if this is a new playlist.
3171 for (i = playlists.begin(); i != playlists.end(); ++i) {
3172 if ((*i).playlist == playlist) {
3177 if (i == playlists.end()) {
3179 PlaylistState before;
3180 before.playlist = playlist;
3181 before.before = &playlist->get_state();
3183 playlist->freeze ();
3184 playlists.push_back(before);
3187 //Partition on the region bounds
3188 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3190 //Re-add region that was just removed due to the partition operation
3191 playlist->add_region( (*rl), (*rl)->first_frame() );
3194 vector<PlaylistState>::iterator pl;
3196 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3197 (*pl).playlist->thaw ();
3198 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3201 commit_reversible_command ();
3205 Editor::crop_region_to_selection ()
3207 if (!selection->time.empty()) {
3209 crop_region_to (selection->time.start(), selection->time.end_frame());
3216 if (get_edit_op_range (start, end)) {
3217 crop_region_to (start, end);
3224 Editor::crop_region_to (framepos_t start, framepos_t end)
3226 vector<boost::shared_ptr<Playlist> > playlists;
3227 boost::shared_ptr<Playlist> playlist;
3230 if (selection->tracks.empty()) {
3231 ts = track_views.filter_to_unique_playlists();
3233 ts = selection->tracks.filter_to_unique_playlists ();
3236 sort_track_selection (ts);
3238 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3240 RouteTimeAxisView* rtv;
3242 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3244 boost::shared_ptr<Track> t = rtv->track();
3246 if (t != 0 && ! t->destructive()) {
3248 if ((playlist = rtv->playlist()) != 0) {
3249 playlists.push_back (playlist);
3255 if (playlists.empty()) {
3259 framepos_t the_start;
3262 bool in_command = false;
3264 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3266 /* Only the top regions at start and end have to be cropped */
3267 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3268 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3270 vector<boost::shared_ptr<Region>> regions;
3272 if (region_at_start != 0) {
3273 regions.push_back (region_at_start);
3275 if (region_at_end != 0) {
3276 regions.push_back (region_at_end);
3279 /* now adjust lengths */
3280 for (vector<boost::shared_ptr<Region>>::iterator i = regions.begin(); i != regions.end(); ++i) {
3282 the_start = max (start, (framepos_t) (*i)->position());
3283 if (max_framepos - the_start < (*i)->length()) {
3284 the_end = the_start + (*i)->length() - 1;
3286 the_end = max_framepos;
3288 the_end = min (end, the_end);
3289 cnt = the_end - the_start + 1;
3292 begin_reversible_command (_("trim to selection"));
3295 (*i)->clear_changes ();
3296 (*i)->trim_to (the_start, cnt);
3297 _session->add_command (new StatefulDiffCommand (*i));
3302 commit_reversible_command ();
3307 Editor::region_fill_track ()
3309 RegionSelection rs = get_regions_from_selection_and_entered ();
3311 if (!_session || rs.empty()) {
3315 framepos_t const end = _session->current_end_frame ();
3316 RegionSelection foo;
3317 bool in_command = false;
3319 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3321 boost::shared_ptr<Region> region ((*i)->region());
3323 boost::shared_ptr<Playlist> pl = region->playlist();
3325 if (end <= region->last_frame()) {
3329 double times = (double) (end - region->last_frame()) / (double) region->length();
3336 begin_reversible_command (Operations::region_fill);
3339 TimeAxisView& tv = (*i)->get_time_axis_view();
3340 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3341 latest_regionviews.clear ();
3342 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3344 pl->clear_changes ();
3345 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3346 _session->add_command (new StatefulDiffCommand (pl));
3350 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3355 selection->set (foo);
3357 commit_reversible_command ();
3362 Editor::region_fill_selection ()
3364 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3368 if (selection->time.empty()) {
3372 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3377 framepos_t start = selection->time[clicked_selection].start;
3378 framepos_t end = selection->time[clicked_selection].end;
3380 boost::shared_ptr<Playlist> playlist;
3382 if (selection->tracks.empty()) {
3386 framepos_t selection_length = end - start;
3387 float times = (float)selection_length / region->length();
3388 bool in_command = false;
3390 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3391 RegionSelection foo;
3393 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3395 if ((playlist = (*i)->playlist()) == 0) {
3400 begin_reversible_command (Operations::fill_selection);
3403 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3404 latest_regionviews.clear ();
3405 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3407 playlist->clear_changes ();
3408 playlist->add_region (RegionFactory::create (region, true), start, times);
3409 _session->add_command (new StatefulDiffCommand (playlist));
3411 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3416 selection->set (foo);
3418 commit_reversible_command ();
3423 Editor::set_region_sync_position ()
3425 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3429 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3431 bool in_command = false;
3433 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3435 if (!(*r)->region()->covers (where)) {
3439 boost::shared_ptr<Region> region ((*r)->region());
3442 begin_reversible_command (_("set sync point"));
3446 region->clear_changes ();
3447 region->set_sync_position (where);
3448 _session->add_command(new StatefulDiffCommand (region));
3452 commit_reversible_command ();
3456 /** Remove the sync positions of the selection */
3458 Editor::remove_region_sync ()
3460 RegionSelection rs = get_regions_from_selection_and_entered ();
3466 begin_reversible_command (_("remove region sync"));
3468 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3470 (*i)->region()->clear_changes ();
3471 (*i)->region()->clear_sync_position ();
3472 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3475 commit_reversible_command ();
3479 Editor::naturalize_region ()
3481 RegionSelection rs = get_regions_from_selection_and_entered ();
3487 if (rs.size() > 1) {
3488 begin_reversible_command (_("move regions to original position"));
3490 begin_reversible_command (_("move region to original position"));
3493 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3494 (*i)->region()->clear_changes ();
3495 (*i)->region()->move_to_natural_position ();
3496 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3499 commit_reversible_command ();
3503 Editor::align_regions (RegionPoint what)
3505 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3511 begin_reversible_command (_("align selection"));
3513 framepos_t const position = get_preferred_edit_position ();
3515 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3516 align_region_internal ((*i)->region(), what, position);
3519 commit_reversible_command ();
3522 struct RegionSortByTime {
3523 bool operator() (const RegionView* a, const RegionView* b) {
3524 return a->region()->position() < b->region()->position();
3529 Editor::align_regions_relative (RegionPoint point)
3531 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3537 framepos_t const position = get_preferred_edit_position ();
3539 framepos_t distance = 0;
3543 list<RegionView*> sorted;
3544 rs.by_position (sorted);
3546 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3551 if (position > r->position()) {
3552 distance = position - r->position();
3554 distance = r->position() - position;
3560 if (position > r->last_frame()) {
3561 distance = position - r->last_frame();
3562 pos = r->position() + distance;
3564 distance = r->last_frame() - position;
3565 pos = r->position() - distance;
3571 pos = r->adjust_to_sync (position);
3572 if (pos > r->position()) {
3573 distance = pos - r->position();
3575 distance = r->position() - pos;
3581 if (pos == r->position()) {
3585 begin_reversible_command (_("align selection (relative)"));
3587 /* move first one specially */
3589 r->clear_changes ();
3590 r->set_position (pos);
3591 _session->add_command(new StatefulDiffCommand (r));
3593 /* move rest by the same amount */
3597 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3599 boost::shared_ptr<Region> region ((*i)->region());
3601 region->clear_changes ();
3604 region->set_position (region->position() + distance);
3606 region->set_position (region->position() - distance);
3609 _session->add_command(new StatefulDiffCommand (region));
3613 commit_reversible_command ();
3617 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3619 begin_reversible_command (_("align region"));
3620 align_region_internal (region, point, position);
3621 commit_reversible_command ();
3625 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3627 region->clear_changes ();
3631 region->set_position (region->adjust_to_sync (position));
3635 if (position > region->length()) {
3636 region->set_position (position - region->length());
3641 region->set_position (position);
3645 _session->add_command(new StatefulDiffCommand (region));
3649 Editor::trim_region_front ()
3655 Editor::trim_region_back ()
3657 trim_region (false);
3661 Editor::trim_region (bool front)
3663 framepos_t where = get_preferred_edit_position();
3664 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3670 begin_reversible_command (front ? _("trim front") : _("trim back"));
3672 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3673 if (!(*i)->region()->locked()) {
3675 (*i)->region()->clear_changes ();
3678 (*i)->region()->trim_front (where);
3679 maybe_locate_with_edit_preroll ( where );
3681 (*i)->region()->trim_end (where);
3682 maybe_locate_with_edit_preroll ( where );
3685 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3689 commit_reversible_command ();
3692 /** Trim the end of the selected regions to the position of the edit cursor */
3694 Editor::trim_region_to_loop ()
3696 Location* loc = _session->locations()->auto_loop_location();
3700 trim_region_to_location (*loc, _("trim to loop"));
3704 Editor::trim_region_to_punch ()
3706 Location* loc = _session->locations()->auto_punch_location();
3710 trim_region_to_location (*loc, _("trim to punch"));
3714 Editor::trim_region_to_location (const Location& loc, const char* str)
3716 RegionSelection rs = get_regions_from_selection_and_entered ();
3717 bool in_command = false;
3719 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3720 RegionView* rv = (*x);
3722 /* require region to span proposed trim */
3723 switch (rv->region()->coverage (loc.start(), loc.end())) {
3724 case Evoral::OverlapInternal:
3730 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3739 if (tav->track() != 0) {
3740 speed = tav->track()->speed();
3743 start = session_frame_to_track_frame (loc.start(), speed);
3744 end = session_frame_to_track_frame (loc.end(), speed);
3746 rv->region()->clear_changes ();
3747 rv->region()->trim_to (start, (end - start));
3750 begin_reversible_command (str);
3753 _session->add_command(new StatefulDiffCommand (rv->region()));
3757 commit_reversible_command ();
3762 Editor::trim_region_to_previous_region_end ()
3764 return trim_to_region(false);
3768 Editor::trim_region_to_next_region_start ()
3770 return trim_to_region(true);
3774 Editor::trim_to_region(bool forward)
3776 RegionSelection rs = get_regions_from_selection_and_entered ();
3777 bool in_command = false;
3779 boost::shared_ptr<Region> next_region;
3781 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3783 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3789 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3797 if (atav->track() != 0) {
3798 speed = atav->track()->speed();
3802 boost::shared_ptr<Region> region = arv->region();
3803 boost::shared_ptr<Playlist> playlist (region->playlist());
3805 region->clear_changes ();
3809 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3815 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3816 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3820 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3826 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3828 arv->region_changed (ARDOUR::bounds_change);
3832 begin_reversible_command (_("trim to region"));
3835 _session->add_command(new StatefulDiffCommand (region));
3839 commit_reversible_command ();
3844 Editor::unfreeze_route ()
3846 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3850 clicked_routeview->track()->unfreeze ();
3854 Editor::_freeze_thread (void* arg)
3856 return static_cast<Editor*>(arg)->freeze_thread ();
3860 Editor::freeze_thread ()
3862 /* create event pool because we may need to talk to the session */
3863 SessionEvent::create_per_thread_pool ("freeze events", 64);
3864 /* create per-thread buffers for process() tree to use */
3865 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3866 current_interthread_info->done = true;
3871 Editor::freeze_route ()
3877 /* stop transport before we start. this is important */
3879 _session->request_transport_speed (0.0);
3881 /* wait for just a little while, because the above call is asynchronous */
3883 Glib::usleep (250000);
3885 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3889 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3891 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3892 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3894 d.set_title (_("Cannot freeze"));
3899 if (clicked_routeview->track()->has_external_redirects()) {
3900 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"
3901 "Freezing will only process the signal as far as the first send/insert/return."),
3902 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3904 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3905 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3906 d.set_title (_("Freeze Limits"));
3908 int response = d.run ();
3911 case Gtk::RESPONSE_CANCEL:
3918 InterThreadInfo itt;
3919 current_interthread_info = &itt;
3921 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3923 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3925 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3927 while (!itt.done && !itt.cancel) {
3928 gtk_main_iteration ();
3931 current_interthread_info = 0;
3935 Editor::bounce_range_selection (bool replace, bool enable_processing)
3937 if (selection->time.empty()) {
3941 TrackSelection views = selection->tracks;
3943 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3945 if (enable_processing) {
3947 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3949 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3951 _("You can't perform this operation because the processing of the signal "
3952 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3953 "You can do this without processing, which is a different operation.")
3955 d.set_title (_("Cannot bounce"));
3962 framepos_t start = selection->time[clicked_selection].start;
3963 framepos_t end = selection->time[clicked_selection].end;
3964 framepos_t cnt = end - start + 1;
3965 bool in_command = false;
3967 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3969 RouteTimeAxisView* rtv;
3971 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3975 boost::shared_ptr<Playlist> playlist;
3977 if ((playlist = rtv->playlist()) == 0) {
3981 InterThreadInfo itt;
3983 playlist->clear_changes ();
3984 playlist->clear_owned_changes ();
3986 boost::shared_ptr<Region> r;
3988 if (enable_processing) {
3989 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3991 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3999 list<AudioRange> ranges;
4000 ranges.push_back (AudioRange (start, start+cnt, 0));
4001 playlist->cut (ranges); // discard result
4002 playlist->add_region (r, start);
4006 begin_reversible_command (_("bounce range"));
4009 vector<Command*> cmds;
4010 playlist->rdiff (cmds);
4011 _session->add_commands (cmds);
4013 _session->add_command (new StatefulDiffCommand (playlist));
4017 commit_reversible_command ();
4021 /** Delete selected regions, automation points or a time range */
4025 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4026 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4027 bool deleted = false;
4028 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4029 deleted = current_mixer_strip->delete_processors ();
4035 /** Cut selected regions, automation points or a time range */
4042 /** Copy selected regions, automation points or a time range */
4050 /** @return true if a Cut, Copy or Clear is possible */
4052 Editor::can_cut_copy () const
4054 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4061 /** Cut, copy or clear selected regions, automation points or a time range.
4062 * @param op Operation (Delete, Cut, Copy or Clear)
4065 Editor::cut_copy (CutCopyOp op)
4067 /* only cancel selection if cut/copy is successful.*/
4073 opname = _("delete");
4082 opname = _("clear");
4086 /* if we're deleting something, and the mouse is still pressed,
4087 the thing we started a drag for will be gone when we release
4088 the mouse button(s). avoid this. see part 2 at the end of
4092 if (op == Delete || op == Cut || op == Clear) {
4093 if (_drags->active ()) {
4098 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4099 cut_buffer->clear ();
4101 if (entered_marker) {
4103 /* cut/delete op while pointing at a marker */
4106 Location* loc = find_location_from_marker (entered_marker, ignored);
4108 if (_session && loc) {
4109 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4116 switch (mouse_mode) {
4119 begin_reversible_command (opname + ' ' + X_("MIDI"));
4121 commit_reversible_command ();
4127 bool did_edit = false;
4129 if (!selection->regions.empty() || !selection->points.empty()) {
4130 begin_reversible_command (opname + ' ' + _("objects"));
4133 if (!selection->regions.empty()) {
4134 cut_copy_regions (op, selection->regions);
4136 if (op == Cut || op == Delete) {
4137 selection->clear_regions ();
4141 if (!selection->points.empty()) {
4142 cut_copy_points (op);
4144 if (op == Cut || op == Delete) {
4145 selection->clear_points ();
4148 } else if (selection->time.empty()) {
4149 framepos_t start, end;
4150 /* no time selection, see if we can get an edit range
4153 if (get_edit_op_range (start, end)) {
4154 selection->set (start, end);
4156 } else if (!selection->time.empty()) {
4157 begin_reversible_command (opname + ' ' + _("range"));
4160 cut_copy_ranges (op);
4162 if (op == Cut || op == Delete) {
4163 selection->clear_time ();
4168 /* reset repeated paste state */
4171 commit_reversible_command ();
4174 if (op == Delete || op == Cut || op == Clear) {
4179 struct AutomationRecord {
4180 AutomationRecord () : state (0) , line(NULL) {}
4181 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4183 XMLNode* state; ///< state before any operation
4184 const AutomationLine* line; ///< line this came from
4185 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4188 /** Cut, copy or clear selected automation points.
4189 * @param op Operation (Cut, Copy or Clear)
4192 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4194 if (selection->points.empty ()) {
4198 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4199 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4201 /* Keep a record of the AutomationLists that we end up using in this operation */
4202 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4205 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4206 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4207 const AutomationLine& line = (*i)->line();
4208 const boost::shared_ptr<AutomationList> al = line.the_list();
4209 if (lists.find (al) == lists.end ()) {
4210 /* We haven't seen this list yet, so make a record for it. This includes
4211 taking a copy of its current state, in case this is needed for undo later.
4213 lists[al] = AutomationRecord (&al->get_state (), &line);
4217 if (op == Cut || op == Copy) {
4218 /* This operation will involve putting things in the cut buffer, so create an empty
4219 ControlList for each of our source lists to put the cut buffer data in.
4221 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4222 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4225 /* Add all selected points to the relevant copy ControlLists */
4226 framepos_t start = std::numeric_limits<framepos_t>::max();
4227 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4228 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4229 AutomationList::const_iterator j = (*i)->model();
4231 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4233 /* Update earliest MIDI start time in beats */
4234 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4236 /* Update earliest session start time in frames */
4237 start = std::min(start, (*i)->line().session_position(j));
4241 /* Snap start time backwards, so copy/paste is snap aligned. */
4243 if (earliest == Evoral::Beats::max()) {
4244 earliest = Evoral::Beats(); // Weird... don't offset
4246 earliest.round_down_to_beat();
4248 if (start == std::numeric_limits<double>::max()) {
4249 start = 0; // Weird... don't offset
4251 snap_to(start, RoundDownMaybe);
4254 const double line_offset = midi ? earliest.to_double() : start;
4255 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4256 /* Correct this copy list so that it is relative to the earliest
4257 start time, so relative ordering between points is preserved
4258 when copying from several lists and the paste starts at the
4259 earliest copied piece of data. */
4260 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4261 (*j)->when -= line_offset;
4264 /* And add it to the cut buffer */
4265 cut_buffer->add (i->second.copy);
4269 if (op == Delete || op == Cut) {
4270 /* This operation needs to remove things from the main AutomationList, so do that now */
4272 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4273 i->first->freeze ();
4276 /* Remove each selected point from its AutomationList */
4277 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4278 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4279 al->erase ((*i)->model ());
4282 /* Thaw the lists and add undo records for them */
4283 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4284 boost::shared_ptr<AutomationList> al = i->first;
4286 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4291 /** Cut, copy or clear selected automation points.
4292 * @param op Operation (Cut, Copy or Clear)
4295 Editor::cut_copy_midi (CutCopyOp op)
4297 Evoral::Beats earliest = Evoral::Beats::max();
4298 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4299 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4301 if (!mrv->selection().empty()) {
4302 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4304 mrv->cut_copy_clear (op);
4306 /* XXX: not ideal, as there may be more than one track involved in the selection */
4307 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4311 if (!selection->points.empty()) {
4312 cut_copy_points (op, earliest, true);
4313 if (op == Cut || op == Delete) {
4314 selection->clear_points ();
4319 struct lt_playlist {
4320 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4321 return a.playlist < b.playlist;
4325 struct PlaylistMapping {
4327 boost::shared_ptr<Playlist> pl;
4329 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4332 /** Remove `clicked_regionview' */
4334 Editor::remove_clicked_region ()
4336 if (clicked_routeview == 0 || clicked_regionview == 0) {
4340 begin_reversible_command (_("remove region"));
4342 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4344 playlist->clear_changes ();
4345 playlist->clear_owned_changes ();
4346 playlist->remove_region (clicked_regionview->region());
4347 if (Config->get_edit_mode() == Ripple)
4348 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4350 /* We might have removed regions, which alters other regions' layering_index,
4351 so we need to do a recursive diff here.
4353 vector<Command*> cmds;
4354 playlist->rdiff (cmds);
4355 _session->add_commands (cmds);
4357 _session->add_command(new StatefulDiffCommand (playlist));
4358 commit_reversible_command ();
4362 /** Remove the selected regions */
4364 Editor::remove_selected_regions ()
4366 RegionSelection rs = get_regions_from_selection_and_entered ();
4368 if (!_session || rs.empty()) {
4372 list<boost::shared_ptr<Region> > regions_to_remove;
4374 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4375 // we can't just remove the region(s) in this loop because
4376 // this removes them from the RegionSelection, and they thus
4377 // disappear from underneath the iterator, and the ++i above
4378 // SEGVs in a puzzling fashion.
4380 // so, first iterate over the regions to be removed from rs and
4381 // add them to the regions_to_remove list, and then
4382 // iterate over the list to actually remove them.
4384 regions_to_remove.push_back ((*i)->region());
4387 vector<boost::shared_ptr<Playlist> > playlists;
4389 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4391 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4394 // is this check necessary?
4398 /* get_regions_from_selection_and_entered() guarantees that
4399 the playlists involved are unique, so there is no need
4403 playlists.push_back (playlist);
4405 playlist->clear_changes ();
4406 playlist->clear_owned_changes ();
4407 playlist->freeze ();
4408 playlist->remove_region (*rl);
4409 if (Config->get_edit_mode() == Ripple)
4410 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4414 vector<boost::shared_ptr<Playlist> >::iterator pl;
4415 bool in_command = false;
4417 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4420 /* We might have removed regions, which alters other regions' layering_index,
4421 so we need to do a recursive diff here.
4425 begin_reversible_command (_("remove region"));
4428 vector<Command*> cmds;
4429 (*pl)->rdiff (cmds);
4430 _session->add_commands (cmds);
4432 _session->add_command(new StatefulDiffCommand (*pl));
4436 commit_reversible_command ();
4440 /** Cut, copy or clear selected regions.
4441 * @param op Operation (Cut, Copy or Clear)
4444 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4446 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4447 a map when we want ordered access to both elements. i think.
4450 vector<PlaylistMapping> pmap;
4452 framepos_t first_position = max_framepos;
4454 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4455 FreezeList freezelist;
4457 /* get ordering correct before we cut/copy */
4459 rs.sort_by_position_and_track ();
4461 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4463 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4465 if (op == Cut || op == Clear || op == Delete) {
4466 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4469 FreezeList::iterator fl;
4471 // only take state if this is a new playlist.
4472 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4478 if (fl == freezelist.end()) {
4479 pl->clear_changes();
4480 pl->clear_owned_changes ();
4482 freezelist.insert (pl);
4487 TimeAxisView* tv = &(*x)->get_time_axis_view();
4488 vector<PlaylistMapping>::iterator z;
4490 for (z = pmap.begin(); z != pmap.end(); ++z) {
4491 if ((*z).tv == tv) {
4496 if (z == pmap.end()) {
4497 pmap.push_back (PlaylistMapping (tv));
4501 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4503 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4506 /* region not yet associated with a playlist (e.g. unfinished
4513 TimeAxisView& tv = (*x)->get_time_axis_view();
4514 boost::shared_ptr<Playlist> npl;
4515 RegionSelection::iterator tmp;
4522 vector<PlaylistMapping>::iterator z;
4524 for (z = pmap.begin(); z != pmap.end(); ++z) {
4525 if ((*z).tv == &tv) {
4530 assert (z != pmap.end());
4533 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4541 boost::shared_ptr<Region> r = (*x)->region();
4542 boost::shared_ptr<Region> _xx;
4548 pl->remove_region (r);
4549 if (Config->get_edit_mode() == Ripple)
4550 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4554 _xx = RegionFactory::create (r);
4555 npl->add_region (_xx, r->position() - first_position);
4556 pl->remove_region (r);
4557 if (Config->get_edit_mode() == Ripple)
4558 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4562 /* copy region before adding, so we're not putting same object into two different playlists */
4563 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4567 pl->remove_region (r);
4568 if (Config->get_edit_mode() == Ripple)
4569 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4578 list<boost::shared_ptr<Playlist> > foo;
4580 /* the pmap is in the same order as the tracks in which selected regions occured */
4582 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4585 foo.push_back ((*i).pl);
4590 cut_buffer->set (foo);
4594 _last_cut_copy_source_track = 0;
4596 _last_cut_copy_source_track = pmap.front().tv;
4600 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4603 /* We might have removed regions, which alters other regions' layering_index,
4604 so we need to do a recursive diff here.
4606 vector<Command*> cmds;
4607 (*pl)->rdiff (cmds);
4608 _session->add_commands (cmds);
4610 _session->add_command (new StatefulDiffCommand (*pl));
4615 Editor::cut_copy_ranges (CutCopyOp op)
4617 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4619 /* Sort the track selection now, so that it if is used, the playlists
4620 selected by the calls below to cut_copy_clear are in the order that
4621 their tracks appear in the editor. This makes things like paste
4622 of ranges work properly.
4625 sort_track_selection (ts);
4628 if (!entered_track) {
4631 ts.push_back (entered_track);
4634 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4635 (*i)->cut_copy_clear (*selection, op);
4640 Editor::paste (float times, bool from_context)
4642 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4644 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4648 Editor::mouse_paste ()
4653 if (!mouse_frame (where, ignored)) {
4658 paste_internal (where, 1);
4662 Editor::paste_internal (framepos_t position, float times)
4664 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4666 if (cut_buffer->empty(internal_editing())) {
4670 if (position == max_framepos) {
4671 position = get_preferred_edit_position();
4672 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4675 if (position == last_paste_pos) {
4676 /* repeated paste in the same position */
4679 /* paste in new location, reset repeated paste state */
4681 last_paste_pos = position;
4684 /* get everything in the correct order */
4687 if (!selection->tracks.empty()) {
4688 /* If there is a track selection, paste into exactly those tracks and
4689 only those tracks. This allows the user to be explicit and override
4690 the below "do the reasonable thing" logic. */
4691 ts = selection->tracks.filter_to_unique_playlists ();
4692 sort_track_selection (ts);
4694 /* Figure out which track to base the paste at. */
4695 TimeAxisView* base_track = NULL;
4696 if (_edit_point == Editing::EditAtMouse && entered_track) {
4697 /* With the mouse edit point, paste onto the track under the mouse. */
4698 base_track = entered_track;
4699 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4700 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4701 base_track = &entered_regionview->get_time_axis_view();
4702 } else if (_last_cut_copy_source_track) {
4703 /* Paste to the track that the cut/copy came from (see mantis #333). */
4704 base_track = _last_cut_copy_source_track;
4706 /* This is "impossible" since we've copied... well, do nothing. */
4710 /* Walk up to parent if necessary, so base track is a route. */
4711 while (base_track->get_parent()) {
4712 base_track = base_track->get_parent();
4715 /* Add base track and all tracks below it. The paste logic will select
4716 the appropriate object types from the cut buffer in relative order. */
4717 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4718 if ((*i)->order() >= base_track->order()) {
4723 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4724 sort_track_selection (ts);
4726 /* Add automation children of each track in order, for pasting several lines. */
4727 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4728 /* Add any automation children for pasting several lines */
4729 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4734 typedef RouteTimeAxisView::AutomationTracks ATracks;
4735 const ATracks& atracks = rtv->automation_tracks();
4736 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4737 i = ts.insert(i, a->second.get());
4742 /* We now have a list of trackviews starting at base_track, including
4743 automation children, in the order shown in the editor, e.g. R1,
4744 R1.A1, R1.A2, R2, R2.A1, ... */
4747 begin_reversible_command (Operations::paste);
4749 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4750 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4751 /* Only one line copied, and one automation track selected. Do a
4752 "greedy" paste from one automation type to another. */
4754 PasteContext ctx(paste_count, times, ItemCounts(), true);
4755 ts.front()->paste (position, *cut_buffer, ctx);
4759 /* Paste into tracks */
4761 PasteContext ctx(paste_count, times, ItemCounts(), false);
4762 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4763 (*i)->paste (position, *cut_buffer, ctx);
4767 commit_reversible_command ();
4771 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4773 if (regions.empty ()) {
4777 boost::shared_ptr<Playlist> playlist;
4778 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4779 RegionSelection foo;
4781 framepos_t const start_frame = regions.start ();
4782 framepos_t const end_frame = regions.end_frame ();
4783 framecnt_t const gap = end_frame - start_frame + 1;
4785 begin_reversible_command (Operations::duplicate_region);
4787 selection->clear_regions ();
4789 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4791 boost::shared_ptr<Region> r ((*i)->region());
4793 TimeAxisView& tv = (*i)->get_time_axis_view();
4794 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4795 latest_regionviews.clear ();
4796 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4798 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4799 playlist = (*i)->region()->playlist();
4800 playlist->clear_changes ();
4801 playlist->duplicate (r, position, gap, times);
4802 _session->add_command(new StatefulDiffCommand (playlist));
4806 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4810 selection->set (foo);
4813 commit_reversible_command ();
4817 Editor::duplicate_selection (float times)
4819 if (selection->time.empty() || selection->tracks.empty()) {
4823 boost::shared_ptr<Playlist> playlist;
4824 vector<boost::shared_ptr<Region> > new_regions;
4825 vector<boost::shared_ptr<Region> >::iterator ri;
4827 create_region_from_selection (new_regions);
4829 if (new_regions.empty()) {
4833 ri = new_regions.begin();
4835 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4836 bool in_command = false;
4838 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4839 if ((playlist = (*i)->playlist()) == 0) {
4842 playlist->clear_changes ();
4844 if (clicked_selection) {
4845 end = selection->time[clicked_selection].end;
4847 end = selection->time.end_frame();
4849 playlist->duplicate (*ri, end + 1, times);
4852 begin_reversible_command (_("duplicate selection"));
4855 _session->add_command (new StatefulDiffCommand (playlist));
4858 if (ri == new_regions.end()) {
4864 commit_reversible_command ();
4868 /** Reset all selected points to the relevant default value */
4870 Editor::reset_point_selection ()
4872 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4873 ARDOUR::AutomationList::iterator j = (*i)->model ();
4874 (*j)->value = (*i)->line().the_list()->default_value ();
4879 Editor::center_playhead ()
4881 float const page = _visible_canvas_width * samples_per_pixel;
4882 center_screen_internal (playhead_cursor->current_frame (), page);
4886 Editor::center_edit_point ()
4888 float const page = _visible_canvas_width * samples_per_pixel;
4889 center_screen_internal (get_preferred_edit_position(), page);
4892 /** Caller must begin and commit a reversible command */
4894 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4896 playlist->clear_changes ();
4898 _session->add_command (new StatefulDiffCommand (playlist));
4902 Editor::nudge_track (bool use_edit, bool forwards)
4904 boost::shared_ptr<Playlist> playlist;
4905 framepos_t distance;
4906 framepos_t next_distance;
4910 start = get_preferred_edit_position();
4915 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4919 if (selection->tracks.empty()) {
4923 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4924 bool in_command = false;
4926 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4928 if ((playlist = (*i)->playlist()) == 0) {
4932 playlist->clear_changes ();
4933 playlist->clear_owned_changes ();
4935 playlist->nudge_after (start, distance, forwards);
4938 begin_reversible_command (_("nudge track"));
4941 vector<Command*> cmds;
4943 playlist->rdiff (cmds);
4944 _session->add_commands (cmds);
4946 _session->add_command (new StatefulDiffCommand (playlist));
4950 commit_reversible_command ();
4955 Editor::remove_last_capture ()
4957 vector<string> choices;
4964 if (Config->get_verify_remove_last_capture()) {
4965 prompt = _("Do you really want to destroy the last capture?"
4966 "\n(This is destructive and cannot be undone)");
4968 choices.push_back (_("No, do nothing."));
4969 choices.push_back (_("Yes, destroy it."));
4971 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4973 if (prompter.run () == 1) {
4974 _session->remove_last_capture ();
4975 _regions->redisplay ();
4979 _session->remove_last_capture();
4980 _regions->redisplay ();
4985 Editor::normalize_region ()
4991 RegionSelection rs = get_regions_from_selection_and_entered ();
4997 NormalizeDialog dialog (rs.size() > 1);
4999 if (dialog.run () == RESPONSE_CANCEL) {
5003 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5006 /* XXX: should really only count audio regions here */
5007 int const regions = rs.size ();
5009 /* Make a list of the selected audio regions' maximum amplitudes, and also
5010 obtain the maximum amplitude of them all.
5012 list<double> max_amps;
5014 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5015 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5017 dialog.descend (1.0 / regions);
5018 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5021 /* the user cancelled the operation */
5025 max_amps.push_back (a);
5026 max_amp = max (max_amp, a);
5031 list<double>::const_iterator a = max_amps.begin ();
5032 bool in_command = false;
5034 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5035 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5040 arv->region()->clear_changes ();
5042 double const amp = dialog.normalize_individually() ? *a : max_amp;
5044 arv->audio_region()->normalize (amp, dialog.target ());
5047 begin_reversible_command (_("normalize"));
5050 _session->add_command (new StatefulDiffCommand (arv->region()));
5056 commit_reversible_command ();
5062 Editor::reset_region_scale_amplitude ()
5068 RegionSelection rs = get_regions_from_selection_and_entered ();
5074 bool in_command = false;
5076 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5077 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5080 arv->region()->clear_changes ();
5081 arv->audio_region()->set_scale_amplitude (1.0f);
5084 begin_reversible_command ("reset gain");
5087 _session->add_command (new StatefulDiffCommand (arv->region()));
5091 commit_reversible_command ();
5096 Editor::adjust_region_gain (bool up)
5098 RegionSelection rs = get_regions_from_selection_and_entered ();
5100 if (!_session || rs.empty()) {
5104 bool in_command = false;
5106 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5107 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5112 arv->region()->clear_changes ();
5114 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5122 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5125 begin_reversible_command ("adjust region gain");
5128 _session->add_command (new StatefulDiffCommand (arv->region()));
5132 commit_reversible_command ();
5138 Editor::reverse_region ()
5144 Reverse rev (*_session);
5145 apply_filter (rev, _("reverse regions"));
5149 Editor::strip_region_silence ()
5155 RegionSelection rs = get_regions_from_selection_and_entered ();
5161 std::list<RegionView*> audio_only;
5163 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5164 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5166 audio_only.push_back (arv);
5170 assert (!audio_only.empty());
5172 StripSilenceDialog d (_session, audio_only);
5173 int const r = d.run ();
5177 if (r == Gtk::RESPONSE_OK) {
5178 ARDOUR::AudioIntervalMap silences;
5179 d.silences (silences);
5180 StripSilence s (*_session, silences, d.fade_length());
5181 apply_filter (s, _("strip silence"), &d);
5186 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5188 Evoral::Sequence<Evoral::Beats>::Notes selected;
5189 mrv.selection_as_notelist (selected, true);
5191 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5192 v.push_back (selected);
5194 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5195 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5197 return op (mrv.midi_region()->model(), pos_beats, v);
5201 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5207 bool in_command = false;
5209 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5210 RegionSelection::const_iterator tmp = r;
5213 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5216 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5219 begin_reversible_command (op.name ());
5223 _session->add_command (cmd);
5231 commit_reversible_command ();
5236 Editor::fork_region ()
5238 RegionSelection rs = get_regions_from_selection_and_entered ();
5244 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5245 bool in_command = false;
5249 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5250 RegionSelection::iterator tmp = r;
5253 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5257 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5258 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5259 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5262 begin_reversible_command (_("Fork Region(s)"));
5265 playlist->clear_changes ();
5266 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5267 _session->add_command(new StatefulDiffCommand (playlist));
5269 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5277 commit_reversible_command ();
5282 Editor::quantize_region ()
5285 quantize_regions(get_regions_from_selection_and_entered ());
5290 Editor::quantize_regions (const RegionSelection& rs)
5292 if (rs.n_midi_regions() == 0) {
5296 if (!quantize_dialog) {
5297 quantize_dialog = new QuantizeDialog (*this);
5300 quantize_dialog->present ();
5301 const int r = quantize_dialog->run ();
5302 quantize_dialog->hide ();
5304 if (r == Gtk::RESPONSE_OK) {
5305 Quantize quant (quantize_dialog->snap_start(),
5306 quantize_dialog->snap_end(),
5307 quantize_dialog->start_grid_size(),
5308 quantize_dialog->end_grid_size(),
5309 quantize_dialog->strength(),
5310 quantize_dialog->swing(),
5311 quantize_dialog->threshold());
5313 apply_midi_note_edit_op (quant, rs);
5318 Editor::legatize_region (bool shrink_only)
5321 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5326 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5328 if (rs.n_midi_regions() == 0) {
5332 Legatize legatize(shrink_only);
5333 apply_midi_note_edit_op (legatize, rs);
5337 Editor::transform_region ()
5340 transform_regions(get_regions_from_selection_and_entered ());
5345 Editor::transform_regions (const RegionSelection& rs)
5347 if (rs.n_midi_regions() == 0) {
5354 const int r = td.run();
5357 if (r == Gtk::RESPONSE_OK) {
5358 Transform transform(td.get());
5359 apply_midi_note_edit_op(transform, rs);
5364 Editor::transpose_region ()
5367 transpose_regions(get_regions_from_selection_and_entered ());
5372 Editor::transpose_regions (const RegionSelection& rs)
5374 if (rs.n_midi_regions() == 0) {
5379 int const r = d.run ();
5381 if (r == RESPONSE_ACCEPT) {
5382 Transpose transpose(d.semitones ());
5383 apply_midi_note_edit_op (transpose, rs);
5388 Editor::insert_patch_change (bool from_context)
5390 RegionSelection rs = get_regions_from_selection_and_entered ();
5396 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5398 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5399 there may be more than one, but the PatchChangeDialog can only offer
5400 one set of patch menus.
5402 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5404 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5405 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5407 if (d.run() == RESPONSE_CANCEL) {
5411 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5412 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5414 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5415 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5422 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5424 RegionSelection rs = get_regions_from_selection_and_entered ();
5430 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5431 bool in_command = false;
5436 int const N = rs.size ();
5438 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5439 RegionSelection::iterator tmp = r;
5442 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5444 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5447 progress->descend (1.0 / N);
5450 if (arv->audio_region()->apply (filter, progress) == 0) {
5452 playlist->clear_changes ();
5453 playlist->clear_owned_changes ();
5455 if (filter.results.empty ()) {
5457 /* no regions returned; remove the old one */
5458 playlist->remove_region (arv->region ());
5462 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5464 /* first region replaces the old one */
5465 playlist->replace_region (arv->region(), *res, (*res)->position());
5469 while (res != filter.results.end()) {
5470 playlist->add_region (*res, (*res)->position());
5475 /* We might have removed regions, which alters other regions' layering_index,
5476 so we need to do a recursive diff here.
5480 begin_reversible_command (command);
5483 vector<Command*> cmds;
5484 playlist->rdiff (cmds);
5485 _session->add_commands (cmds);
5487 _session->add_command(new StatefulDiffCommand (playlist));
5491 progress->ascend ();
5500 commit_reversible_command ();
5505 Editor::external_edit_region ()
5511 Editor::reset_region_gain_envelopes ()
5513 RegionSelection rs = get_regions_from_selection_and_entered ();
5515 if (!_session || rs.empty()) {
5519 bool in_command = false;
5521 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5522 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5524 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5525 XMLNode& before (alist->get_state());
5527 arv->audio_region()->set_default_envelope ();
5530 begin_reversible_command (_("reset region gain"));
5533 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5538 commit_reversible_command ();
5543 Editor::set_region_gain_visibility (RegionView* rv)
5545 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5547 arv->update_envelope_visibility();
5552 Editor::set_gain_envelope_visibility ()
5558 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5559 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5561 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5567 Editor::toggle_gain_envelope_active ()
5569 if (_ignore_region_action) {
5573 RegionSelection rs = get_regions_from_selection_and_entered ();
5575 if (!_session || rs.empty()) {
5579 bool in_command = false;
5581 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5582 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5584 arv->region()->clear_changes ();
5585 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5588 begin_reversible_command (_("region gain envelope active"));
5591 _session->add_command (new StatefulDiffCommand (arv->region()));
5596 commit_reversible_command ();
5601 Editor::toggle_region_lock ()
5603 if (_ignore_region_action) {
5607 RegionSelection rs = get_regions_from_selection_and_entered ();
5609 if (!_session || rs.empty()) {
5613 begin_reversible_command (_("toggle region lock"));
5615 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5616 (*i)->region()->clear_changes ();
5617 (*i)->region()->set_locked (!(*i)->region()->locked());
5618 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5621 commit_reversible_command ();
5625 Editor::toggle_region_video_lock ()
5627 if (_ignore_region_action) {
5631 RegionSelection rs = get_regions_from_selection_and_entered ();
5633 if (!_session || rs.empty()) {
5637 begin_reversible_command (_("Toggle Video Lock"));
5639 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5640 (*i)->region()->clear_changes ();
5641 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5642 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5645 commit_reversible_command ();
5649 Editor::toggle_region_lock_style ()
5651 if (_ignore_region_action) {
5655 RegionSelection rs = get_regions_from_selection_and_entered ();
5657 if (!_session || rs.empty()) {
5661 begin_reversible_command (_("region lock style"));
5663 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5664 (*i)->region()->clear_changes ();
5665 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5666 (*i)->region()->set_position_lock_style (ns);
5667 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5670 commit_reversible_command ();
5674 Editor::toggle_opaque_region ()
5676 if (_ignore_region_action) {
5680 RegionSelection rs = get_regions_from_selection_and_entered ();
5682 if (!_session || rs.empty()) {
5686 begin_reversible_command (_("change region opacity"));
5688 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5689 (*i)->region()->clear_changes ();
5690 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5691 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5694 commit_reversible_command ();
5698 Editor::toggle_record_enable ()
5700 bool new_state = false;
5702 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5703 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5706 if (!rtav->is_track())
5710 new_state = !rtav->track()->record_enabled();
5714 rtav->track()->set_record_enabled (new_state, this);
5719 Editor::toggle_solo ()
5721 bool new_state = false;
5723 boost::shared_ptr<RouteList> rl (new RouteList);
5725 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5726 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5733 new_state = !rtav->route()->soloed ();
5737 rl->push_back (rtav->route());
5740 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5744 Editor::toggle_mute ()
5746 bool new_state = false;
5748 boost::shared_ptr<RouteList> rl (new RouteList);
5750 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5751 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5758 new_state = !rtav->route()->muted();
5762 rl->push_back (rtav->route());
5765 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5769 Editor::toggle_solo_isolate ()
5775 Editor::fade_range ()
5777 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5779 begin_reversible_command (_("fade range"));
5781 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5782 (*i)->fade_range (selection->time);
5785 commit_reversible_command ();
5790 Editor::set_fade_length (bool in)
5792 RegionSelection rs = get_regions_from_selection_and_entered ();
5798 /* we need a region to measure the offset from the start */
5800 RegionView* rv = rs.front ();
5802 framepos_t pos = get_preferred_edit_position();
5806 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5807 /* edit point is outside the relevant region */
5812 if (pos <= rv->region()->position()) {
5816 len = pos - rv->region()->position();
5817 cmd = _("set fade in length");
5819 if (pos >= rv->region()->last_frame()) {
5823 len = rv->region()->last_frame() - pos;
5824 cmd = _("set fade out length");
5827 bool in_command = false;
5829 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5830 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5836 boost::shared_ptr<AutomationList> alist;
5838 alist = tmp->audio_region()->fade_in();
5840 alist = tmp->audio_region()->fade_out();
5843 XMLNode &before = alist->get_state();
5846 tmp->audio_region()->set_fade_in_length (len);
5847 tmp->audio_region()->set_fade_in_active (true);
5849 tmp->audio_region()->set_fade_out_length (len);
5850 tmp->audio_region()->set_fade_out_active (true);
5854 begin_reversible_command (cmd);
5857 XMLNode &after = alist->get_state();
5858 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5862 commit_reversible_command ();
5867 Editor::set_fade_in_shape (FadeShape shape)
5869 RegionSelection rs = get_regions_from_selection_and_entered ();
5874 bool in_command = false;
5876 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5877 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5883 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5884 XMLNode &before = alist->get_state();
5886 tmp->audio_region()->set_fade_in_shape (shape);
5889 begin_reversible_command (_("set fade in shape"));
5892 XMLNode &after = alist->get_state();
5893 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5897 commit_reversible_command ();
5902 Editor::set_fade_out_shape (FadeShape shape)
5904 RegionSelection rs = get_regions_from_selection_and_entered ();
5909 bool in_command = false;
5911 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5912 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5918 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5919 XMLNode &before = alist->get_state();
5921 tmp->audio_region()->set_fade_out_shape (shape);
5924 begin_reversible_command (_("set fade out shape"));
5927 XMLNode &after = alist->get_state();
5928 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5932 commit_reversible_command ();
5937 Editor::set_fade_in_active (bool yn)
5939 RegionSelection rs = get_regions_from_selection_and_entered ();
5944 bool in_command = false;
5946 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5947 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5954 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5956 ar->clear_changes ();
5957 ar->set_fade_in_active (yn);
5960 begin_reversible_command (_("set fade in active"));
5963 _session->add_command (new StatefulDiffCommand (ar));
5967 commit_reversible_command ();
5972 Editor::set_fade_out_active (bool yn)
5974 RegionSelection rs = get_regions_from_selection_and_entered ();
5979 bool in_command = false;
5981 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5982 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5988 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5990 ar->clear_changes ();
5991 ar->set_fade_out_active (yn);
5994 begin_reversible_command (_("set fade out active"));
5997 _session->add_command(new StatefulDiffCommand (ar));
6001 commit_reversible_command ();
6006 Editor::toggle_region_fades (int dir)
6008 if (_ignore_region_action) {
6012 boost::shared_ptr<AudioRegion> ar;
6015 RegionSelection rs = get_regions_from_selection_and_entered ();
6021 RegionSelection::iterator i;
6022 for (i = rs.begin(); i != rs.end(); ++i) {
6023 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6025 yn = ar->fade_out_active ();
6027 yn = ar->fade_in_active ();
6033 if (i == rs.end()) {
6037 /* XXX should this undo-able? */
6038 bool in_command = false;
6040 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6041 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6044 ar->clear_changes ();
6046 if (dir == 1 || dir == 0) {
6047 ar->set_fade_in_active (!yn);
6050 if (dir == -1 || dir == 0) {
6051 ar->set_fade_out_active (!yn);
6054 begin_reversible_command (_("toggle fade active"));
6057 _session->add_command(new StatefulDiffCommand (ar));
6061 commit_reversible_command ();
6066 /** Update region fade visibility after its configuration has been changed */
6068 Editor::update_region_fade_visibility ()
6070 bool _fade_visibility = _session->config.get_show_region_fades ();
6072 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6073 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6075 if (_fade_visibility) {
6076 v->audio_view()->show_all_fades ();
6078 v->audio_view()->hide_all_fades ();
6085 Editor::set_edit_point ()
6090 if (!mouse_frame (where, ignored)) {
6096 if (selection->markers.empty()) {
6098 mouse_add_new_marker (where);
6103 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6106 loc->move_to (where);
6112 Editor::set_playhead_cursor ()
6114 if (entered_marker) {
6115 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6120 if (!mouse_frame (where, ignored)) {
6127 _session->request_locate (where, _session->transport_rolling());
6131 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6132 cancel_time_selection();
6137 Editor::split_region ()
6139 if (_drags->active ()) {
6143 //if a range is selected, separate it
6144 if ( !selection->time.empty()) {
6145 separate_regions_between (selection->time);
6149 //if no range was selected, try to find some regions to split
6150 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6152 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6154 framepos_t where = get_preferred_edit_position ();
6160 split_regions_at (where, rs);
6164 struct EditorOrderRouteSorter {
6165 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6166 return a->order_key () < b->order_key ();
6171 Editor::select_next_route()
6173 if (selection->tracks.empty()) {
6174 selection->set (track_views.front());
6178 TimeAxisView* current = selection->tracks.front();
6182 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6183 if (*i == current) {
6185 if (i != track_views.end()) {
6188 current = (*(track_views.begin()));
6189 //selection->set (*(track_views.begin()));
6194 rui = dynamic_cast<RouteUI *>(current);
6195 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6197 selection->set(current);
6199 ensure_time_axis_view_is_visible (*current, false);
6203 Editor::select_prev_route()
6205 if (selection->tracks.empty()) {
6206 selection->set (track_views.front());
6210 TimeAxisView* current = selection->tracks.front();
6214 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6215 if (*i == current) {
6217 if (i != track_views.rend()) {
6220 current = *(track_views.rbegin());
6225 rui = dynamic_cast<RouteUI *>(current);
6226 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6228 selection->set (current);
6230 ensure_time_axis_view_is_visible (*current, false);
6234 Editor::set_loop_from_selection (bool play)
6236 if (_session == 0) {
6240 framepos_t start, end;
6241 if (!get_selection_extents ( start, end))
6244 set_loop_range (start, end, _("set loop range from selection"));
6247 _session->request_play_loop (true, true);
6252 Editor::set_loop_from_region (bool play)
6254 framepos_t start, end;
6255 if (!get_selection_extents ( start, end))
6258 set_loop_range (start, end, _("set loop range from region"));
6261 _session->request_locate (start, true);
6262 _session->request_play_loop (true);
6267 Editor::set_punch_from_selection ()
6269 if (_session == 0) {
6273 framepos_t start, end;
6274 if (!get_selection_extents ( start, end))
6277 set_punch_range (start, end, _("set punch range from selection"));
6281 Editor::set_session_extents_from_selection ()
6283 if (_session == 0) {
6287 framepos_t start, end;
6288 if (!get_selection_extents ( start, end))
6292 if ((loc = _session->locations()->session_range_location()) == 0) {
6293 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6295 XMLNode &before = loc->get_state();
6297 _session->set_session_extents ( start, end );
6299 XMLNode &after = loc->get_state();
6301 begin_reversible_command (_("set session start/end from selection"));
6303 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6305 commit_reversible_command ();
6310 Editor::set_punch_start_from_edit_point ()
6314 framepos_t start = 0;
6315 framepos_t end = max_framepos;
6317 //use the existing punch end, if any
6318 Location* tpl = transport_punch_location();
6323 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6324 start = _session->audible_frame();
6326 start = get_preferred_edit_position();
6329 //snap the selection start/end
6332 //if there's not already a sensible selection endpoint, go "forever"
6333 if ( start > end ) {
6337 set_punch_range (start, end, _("set punch start from EP"));
6343 Editor::set_punch_end_from_edit_point ()
6347 framepos_t start = 0;
6348 framepos_t end = max_framepos;
6350 //use the existing punch start, if any
6351 Location* tpl = transport_punch_location();
6353 start = tpl->start();
6356 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6357 end = _session->audible_frame();
6359 end = get_preferred_edit_position();
6362 //snap the selection start/end
6365 set_punch_range (start, end, _("set punch end from EP"));
6371 Editor::set_loop_start_from_edit_point ()
6375 framepos_t start = 0;
6376 framepos_t end = max_framepos;
6378 //use the existing loop end, if any
6379 Location* tpl = transport_loop_location();
6384 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6385 start = _session->audible_frame();
6387 start = get_preferred_edit_position();
6390 //snap the selection start/end
6393 //if there's not already a sensible selection endpoint, go "forever"
6394 if ( start > end ) {
6398 set_loop_range (start, end, _("set loop start from EP"));
6404 Editor::set_loop_end_from_edit_point ()
6408 framepos_t start = 0;
6409 framepos_t end = max_framepos;
6411 //use the existing loop start, if any
6412 Location* tpl = transport_loop_location();
6414 start = tpl->start();
6417 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6418 end = _session->audible_frame();
6420 end = get_preferred_edit_position();
6423 //snap the selection start/end
6426 set_loop_range (start, end, _("set loop end from EP"));
6431 Editor::set_punch_from_region ()
6433 framepos_t start, end;
6434 if (!get_selection_extents ( start, end))
6437 set_punch_range (start, end, _("set punch range from region"));
6441 Editor::pitch_shift_region ()
6443 RegionSelection rs = get_regions_from_selection_and_entered ();
6445 RegionSelection audio_rs;
6446 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6447 if (dynamic_cast<AudioRegionView*> (*i)) {
6448 audio_rs.push_back (*i);
6452 if (audio_rs.empty()) {
6456 pitch_shift (audio_rs, 1.2);
6460 Editor::set_tempo_from_region ()
6462 RegionSelection rs = get_regions_from_selection_and_entered ();
6464 if (!_session || rs.empty()) {
6468 RegionView* rv = rs.front();
6470 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6474 Editor::use_range_as_bar ()
6476 framepos_t start, end;
6477 if (get_edit_op_range (start, end)) {
6478 define_one_bar (start, end);
6483 Editor::define_one_bar (framepos_t start, framepos_t end)
6485 framepos_t length = end - start;
6487 const Meter& m (_session->tempo_map().meter_at (start));
6489 /* length = 1 bar */
6491 /* now we want frames per beat.
6492 we have frames per bar, and beats per bar, so ...
6495 /* XXXX METER MATH */
6497 double frames_per_beat = length / m.divisions_per_bar();
6499 /* beats per minute = */
6501 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6503 /* now decide whether to:
6505 (a) set global tempo
6506 (b) add a new tempo marker
6510 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6512 bool do_global = false;
6514 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6516 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6517 at the start, or create a new marker
6520 vector<string> options;
6521 options.push_back (_("Cancel"));
6522 options.push_back (_("Add new marker"));
6523 options.push_back (_("Set global tempo"));
6526 _("Define one bar"),
6527 _("Do you want to set the global tempo or add a new tempo marker?"),
6531 c.set_default_response (2);
6547 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6548 if the marker is at the region starter, change it, otherwise add
6553 begin_reversible_command (_("set tempo from region"));
6554 XMLNode& before (_session->tempo_map().get_state());
6557 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6558 } else if (t.frame() == start) {
6559 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6561 Timecode::BBT_Time bbt;
6562 _session->tempo_map().bbt_time (start, bbt);
6563 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6566 XMLNode& after (_session->tempo_map().get_state());
6568 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6569 commit_reversible_command ();
6573 Editor::split_region_at_transients ()
6575 AnalysisFeatureList positions;
6577 RegionSelection rs = get_regions_from_selection_and_entered ();
6579 if (!_session || rs.empty()) {
6583 begin_reversible_command (_("split regions"));
6585 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6587 RegionSelection::iterator tmp;
6592 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6594 if (ar && (ar->get_transients (positions) == 0)) {
6595 split_region_at_points ((*i)->region(), positions, true);
6602 commit_reversible_command ();
6607 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6609 bool use_rhythmic_rodent = false;
6611 boost::shared_ptr<Playlist> pl = r->playlist();
6613 list<boost::shared_ptr<Region> > new_regions;
6619 if (positions.empty()) {
6624 if (positions.size() > 20 && can_ferret) {
6625 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);
6626 MessageDialog msg (msgstr,
6629 Gtk::BUTTONS_OK_CANCEL);
6632 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6633 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6635 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6638 msg.set_title (_("Excessive split?"));
6641 int response = msg.run();
6647 case RESPONSE_APPLY:
6648 use_rhythmic_rodent = true;
6655 if (use_rhythmic_rodent) {
6656 show_rhythm_ferret ();
6660 AnalysisFeatureList::const_iterator x;
6662 pl->clear_changes ();
6663 pl->clear_owned_changes ();
6665 x = positions.begin();
6667 if (x == positions.end()) {
6672 pl->remove_region (r);
6676 while (x != positions.end()) {
6678 /* deal with positons that are out of scope of present region bounds */
6679 if (*x <= 0 || *x > r->length()) {
6684 /* file start = original start + how far we from the initial position ?
6687 framepos_t file_start = r->start() + pos;
6689 /* length = next position - current position
6692 framepos_t len = (*x) - pos;
6694 /* XXX we do we really want to allow even single-sample regions?
6695 shouldn't we have some kind of lower limit on region size?
6704 if (RegionFactory::region_name (new_name, r->name())) {
6708 /* do NOT announce new regions 1 by one, just wait till they are all done */
6712 plist.add (ARDOUR::Properties::start, file_start);
6713 plist.add (ARDOUR::Properties::length, len);
6714 plist.add (ARDOUR::Properties::name, new_name);
6715 plist.add (ARDOUR::Properties::layer, 0);
6717 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6718 /* because we set annouce to false, manually add the new region to the
6721 RegionFactory::map_add (nr);
6723 pl->add_region (nr, r->position() + pos);
6726 new_regions.push_front(nr);
6735 RegionFactory::region_name (new_name, r->name());
6737 /* Add the final region */
6740 plist.add (ARDOUR::Properties::start, r->start() + pos);
6741 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6742 plist.add (ARDOUR::Properties::name, new_name);
6743 plist.add (ARDOUR::Properties::layer, 0);
6745 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6746 /* because we set annouce to false, manually add the new region to the
6749 RegionFactory::map_add (nr);
6750 pl->add_region (nr, r->position() + pos);
6753 new_regions.push_front(nr);
6758 /* We might have removed regions, which alters other regions' layering_index,
6759 so we need to do a recursive diff here.
6761 vector<Command*> cmds;
6763 _session->add_commands (cmds);
6765 _session->add_command (new StatefulDiffCommand (pl));
6769 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6770 set_selected_regionview_from_region_list ((*i), Selection::Add);
6776 Editor::place_transient()
6782 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6788 framepos_t where = get_preferred_edit_position();
6790 begin_reversible_command (_("place transient"));
6792 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6793 framepos_t position = (*r)->region()->position();
6794 (*r)->region()->add_transient(where - position);
6797 commit_reversible_command ();
6801 Editor::remove_transient(ArdourCanvas::Item* item)
6807 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6810 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6811 _arv->remove_transient (*(float*) _line->get_data ("position"));
6815 Editor::snap_regions_to_grid ()
6817 list <boost::shared_ptr<Playlist > > used_playlists;
6819 RegionSelection rs = get_regions_from_selection_and_entered ();
6821 if (!_session || rs.empty()) {
6825 begin_reversible_command (_("snap regions to grid"));
6827 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6829 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6831 if (!pl->frozen()) {
6832 /* we haven't seen this playlist before */
6834 /* remember used playlists so we can thaw them later */
6835 used_playlists.push_back(pl);
6839 framepos_t start_frame = (*r)->region()->first_frame ();
6840 snap_to (start_frame);
6841 (*r)->region()->set_position (start_frame);
6844 while (used_playlists.size() > 0) {
6845 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6847 used_playlists.pop_front();
6850 commit_reversible_command ();
6854 Editor::close_region_gaps ()
6856 list <boost::shared_ptr<Playlist > > used_playlists;
6858 RegionSelection rs = get_regions_from_selection_and_entered ();
6860 if (!_session || rs.empty()) {
6864 Dialog dialog (_("Close Region Gaps"));
6867 table.set_spacings (12);
6868 table.set_border_width (12);
6869 Label* l = manage (left_aligned_label (_("Crossfade length")));
6870 table.attach (*l, 0, 1, 0, 1);
6872 SpinButton spin_crossfade (1, 0);
6873 spin_crossfade.set_range (0, 15);
6874 spin_crossfade.set_increments (1, 1);
6875 spin_crossfade.set_value (5);
6876 table.attach (spin_crossfade, 1, 2, 0, 1);
6878 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6880 l = manage (left_aligned_label (_("Pull-back length")));
6881 table.attach (*l, 0, 1, 1, 2);
6883 SpinButton spin_pullback (1, 0);
6884 spin_pullback.set_range (0, 100);
6885 spin_pullback.set_increments (1, 1);
6886 spin_pullback.set_value(30);
6887 table.attach (spin_pullback, 1, 2, 1, 2);
6889 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6891 dialog.get_vbox()->pack_start (table);
6892 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6893 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6896 if (dialog.run () == RESPONSE_CANCEL) {
6900 framepos_t crossfade_len = spin_crossfade.get_value();
6901 framepos_t pull_back_frames = spin_pullback.get_value();
6903 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6904 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6906 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6908 begin_reversible_command (_("close region gaps"));
6911 boost::shared_ptr<Region> last_region;
6913 rs.sort_by_position_and_track();
6915 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6917 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6919 if (!pl->frozen()) {
6920 /* we haven't seen this playlist before */
6922 /* remember used playlists so we can thaw them later */
6923 used_playlists.push_back(pl);
6927 framepos_t position = (*r)->region()->position();
6929 if (idx == 0 || position < last_region->position()){
6930 last_region = (*r)->region();
6935 (*r)->region()->trim_front( (position - pull_back_frames));
6936 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6938 last_region = (*r)->region();
6943 while (used_playlists.size() > 0) {
6944 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6946 used_playlists.pop_front();
6949 commit_reversible_command ();
6953 Editor::tab_to_transient (bool forward)
6955 AnalysisFeatureList positions;
6957 RegionSelection rs = get_regions_from_selection_and_entered ();
6963 framepos_t pos = _session->audible_frame ();
6965 if (!selection->tracks.empty()) {
6967 /* don't waste time searching for transients in duplicate playlists.
6970 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6972 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6974 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6977 boost::shared_ptr<Track> tr = rtv->track();
6979 boost::shared_ptr<Playlist> pl = tr->playlist ();
6981 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6984 positions.push_back (result);
6997 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6998 (*r)->region()->get_transients (positions);
7002 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7005 AnalysisFeatureList::iterator x;
7007 for (x = positions.begin(); x != positions.end(); ++x) {
7013 if (x != positions.end ()) {
7014 _session->request_locate (*x);
7018 AnalysisFeatureList::reverse_iterator x;
7020 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7026 if (x != positions.rend ()) {
7027 _session->request_locate (*x);
7033 Editor::playhead_forward_to_grid ()
7039 framepos_t pos = playhead_cursor->current_frame ();
7040 if (pos < max_framepos - 1) {
7042 snap_to_internal (pos, RoundUpAlways, false);
7043 _session->request_locate (pos);
7049 Editor::playhead_backward_to_grid ()
7055 framepos_t pos = playhead_cursor->current_frame ();
7058 snap_to_internal (pos, RoundDownAlways, false);
7059 _session->request_locate (pos);
7064 Editor::set_track_height (Height h)
7066 TrackSelection& ts (selection->tracks);
7068 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7069 (*x)->set_height_enum (h);
7074 Editor::toggle_tracks_active ()
7076 TrackSelection& ts (selection->tracks);
7078 bool target = false;
7084 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7085 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7089 target = !rtv->_route->active();
7092 rtv->_route->set_active (target, this);
7098 Editor::remove_tracks ()
7100 /* this will delete GUI objects that may be the subject of an event
7101 handler in which this method is called. Defer actual deletion to the
7102 next idle callback, when all event handling is finished.
7104 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7108 Editor::idle_remove_tracks ()
7111 return false; /* do not call again */
7115 Editor::_remove_tracks ()
7117 TrackSelection& ts (selection->tracks);
7123 vector<string> choices;
7127 const char* trackstr;
7129 vector<boost::shared_ptr<Route> > routes;
7130 bool special_bus = false;
7132 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7133 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7137 if (rtv->is_track()) {
7142 routes.push_back (rtv->_route);
7144 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7149 if (special_bus && !Config->get_allow_special_bus_removal()) {
7150 MessageDialog msg (_("That would be bad news ...."),
7154 msg.set_secondary_text (string_compose (_(
7155 "Removing the master or monitor bus is such a bad idea\n\
7156 that %1 is not going to allow it.\n\
7158 If you really want to do this sort of thing\n\
7159 edit your ardour.rc file to set the\n\
7160 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7167 if (ntracks + nbusses == 0) {
7171 trackstr = P_("track", "tracks", ntracks);
7172 busstr = P_("bus", "busses", nbusses);
7176 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7177 "(You may also lose the playlists associated with the %2)\n\n"
7178 "This action cannot be undone, and the session file will be overwritten!"),
7179 ntracks, trackstr, nbusses, busstr);
7181 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7182 "(You may also lose the playlists associated with the %2)\n\n"
7183 "This action cannot be undone, and the session file will be overwritten!"),
7186 } else if (nbusses) {
7187 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7188 "This action cannot be undone, and the session file will be overwritten"),
7192 choices.push_back (_("No, do nothing."));
7193 if (ntracks + nbusses > 1) {
7194 choices.push_back (_("Yes, remove them."));
7196 choices.push_back (_("Yes, remove it."));
7201 title = string_compose (_("Remove %1"), trackstr);
7203 title = string_compose (_("Remove %1"), busstr);
7206 Choice prompter (title, prompt, choices);
7208 if (prompter.run () != 1) {
7213 Session::StateProtector sp (_session);
7214 DisplaySuspender ds;
7215 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7216 _session->remove_route (*x);
7222 Editor::do_insert_time ()
7224 if (selection->tracks.empty()) {
7228 InsertRemoveTimeDialog d (*this);
7229 int response = d.run ();
7231 if (response != RESPONSE_OK) {
7235 if (d.distance() == 0) {
7239 InsertTimeOption opt = d.intersected_region_action ();
7242 get_preferred_edit_position(),
7248 d.move_glued_markers(),
7249 d.move_locked_markers(),
7255 Editor::insert_time (
7256 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7257 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7261 if (Config->get_edit_mode() == Lock) {
7264 bool in_command = false;
7266 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7268 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7272 /* don't operate on any playlist more than once, which could
7273 * happen if "all playlists" is enabled, but there is more
7274 * than 1 track using playlists "from" a given track.
7277 set<boost::shared_ptr<Playlist> > pl;
7279 if (all_playlists) {
7280 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7281 if (rtav && rtav->track ()) {
7282 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7283 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7288 if ((*x)->playlist ()) {
7289 pl.insert ((*x)->playlist ());
7293 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7295 (*i)->clear_changes ();
7296 (*i)->clear_owned_changes ();
7298 if (opt == SplitIntersected) {
7302 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7305 begin_reversible_command (_("insert time"));
7308 vector<Command*> cmds;
7310 _session->add_commands (cmds);
7312 _session->add_command (new StatefulDiffCommand (*i));
7316 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7319 begin_reversible_command (_("insert time"));
7322 rtav->route ()->shift (pos, frames);
7329 XMLNode& before (_session->locations()->get_state());
7330 Locations::LocationList copy (_session->locations()->list());
7332 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7334 Locations::LocationList::const_iterator tmp;
7336 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7337 bool const was_locked = (*i)->locked ();
7338 if (locked_markers_too) {
7342 if ((*i)->start() >= pos) {
7343 // move end first, in case we're moving by more than the length of the range
7344 if (!(*i)->is_mark()) {
7345 (*i)->set_end ((*i)->end() + frames);
7347 (*i)->set_start ((*i)->start() + frames);
7359 begin_reversible_command (_("insert time"));
7362 XMLNode& after (_session->locations()->get_state());
7363 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7369 begin_reversible_command (_("insert time"));
7372 XMLNode& before (_session->tempo_map().get_state());
7373 _session->tempo_map().insert_time (pos, frames);
7374 XMLNode& after (_session->tempo_map().get_state());
7375 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7379 commit_reversible_command ();
7384 Editor::do_remove_time ()
7386 if (selection->tracks.empty()) {
7390 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7391 InsertRemoveTimeDialog d (*this, true);
7393 int response = d.run ();
7395 if (response != RESPONSE_OK) {
7399 framecnt_t distance = d.distance();
7401 if (distance == 0) {
7411 d.move_glued_markers(),
7412 d.move_locked_markers(),
7418 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7419 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7421 if (Config->get_edit_mode() == Lock) {
7422 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7425 bool in_command = false;
7427 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7429 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7433 XMLNode &before = pl->get_state();
7435 std::list<AudioRange> rl;
7436 AudioRange ar(pos, pos+frames, 0);
7439 pl->shift (pos, -frames, true, ignore_music_glue);
7442 begin_reversible_command (_("cut time"));
7445 XMLNode &after = pl->get_state();
7447 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7451 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7454 begin_reversible_command (_("cut time"));
7457 rtav->route ()->shift (pos, -frames);
7461 std::list<Location*> loc_kill_list;
7466 XMLNode& before (_session->locations()->get_state());
7467 Locations::LocationList copy (_session->locations()->list());
7469 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7470 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7472 bool const was_locked = (*i)->locked ();
7473 if (locked_markers_too) {
7477 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7478 if ((*i)->end() >= pos
7479 && (*i)->end() < pos+frames
7480 && (*i)->start() >= pos
7481 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7483 loc_kill_list.push_back(*i);
7484 } else { // only start or end is included, try to do the right thing
7485 // move start before moving end, to avoid trying to move the end to before the start
7486 // if we're removing more time than the length of the range
7487 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7488 // start is within cut
7489 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7491 } else if ((*i)->start() >= pos+frames) {
7492 // start (and thus entire range) lies beyond end of cut
7493 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7496 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7497 // end is inside cut
7498 (*i)->set_end (pos); // bring the end to the cut
7500 } else if ((*i)->end() >= pos+frames) {
7501 // end is beyond end of cut
7502 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7507 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7508 loc_kill_list.push_back(*i);
7510 } else if ((*i)->start() >= pos) {
7511 (*i)->set_start ((*i)->start() -frames);
7521 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7522 _session->locations()->remove( *i );
7527 begin_reversible_command (_("cut time"));
7530 XMLNode& after (_session->locations()->get_state());
7531 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7536 XMLNode& before (_session->tempo_map().get_state());
7538 if (_session->tempo_map().remove_time (pos, frames) ) {
7540 begin_reversible_command (_("remove time"));
7543 XMLNode& after (_session->tempo_map().get_state());
7544 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7549 commit_reversible_command ();
7554 Editor::fit_selection ()
7556 if (!selection->tracks.empty()) {
7557 fit_tracks (selection->tracks);
7561 /* no selected tracks - use tracks with selected regions */
7563 if (!selection->regions.empty()) {
7564 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7565 tvl.push_back (&(*r)->get_time_axis_view ());
7571 } else if (internal_editing()) {
7572 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7575 if (entered_track) {
7576 tvl.push_back (entered_track);
7585 Editor::fit_tracks (TrackViewList & tracks)
7587 if (tracks.empty()) {
7591 uint32_t child_heights = 0;
7592 int visible_tracks = 0;
7594 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7596 if (!(*t)->marked_for_display()) {
7600 child_heights += (*t)->effective_height() - (*t)->current_height();
7604 /* compute the per-track height from:
7606 total canvas visible height -
7607 height that will be taken by visible children of selected
7608 tracks - height of the ruler/hscroll area
7610 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7611 double first_y_pos = DBL_MAX;
7613 if (h < TimeAxisView::preset_height (HeightSmall)) {
7614 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7615 /* too small to be displayed */
7619 undo_visual_stack.push_back (current_visual_state (true));
7620 PBD::Unwinder<bool> nsv (no_save_visual, true);
7622 /* build a list of all tracks, including children */
7625 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7627 TimeAxisView::Children c = (*i)->get_child_list ();
7628 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7629 all.push_back (j->get());
7634 // find selection range.
7635 // if someone knows how to user TrackViewList::iterator for this
7637 int selected_top = -1;
7638 int selected_bottom = -1;
7640 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7641 if ((*t)->marked_for_display ()) {
7642 if (tracks.contains(*t)) {
7643 if (selected_top == -1) {
7646 selected_bottom = i;
7652 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7653 if ((*t)->marked_for_display ()) {
7654 if (tracks.contains(*t)) {
7655 (*t)->set_height (h);
7656 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7658 if (i > selected_top && i < selected_bottom) {
7659 hide_track_in_display (*t);
7666 set the controls_layout height now, because waiting for its size
7667 request signal handler will cause the vertical adjustment setting to fail
7670 controls_layout.property_height () = _full_canvas_height;
7671 vertical_adjustment.set_value (first_y_pos);
7673 redo_visual_stack.push_back (current_visual_state (true));
7675 visible_tracks_selector.set_text (_("Sel"));
7679 Editor::save_visual_state (uint32_t n)
7681 while (visual_states.size() <= n) {
7682 visual_states.push_back (0);
7685 if (visual_states[n] != 0) {
7686 delete visual_states[n];
7689 visual_states[n] = current_visual_state (true);
7694 Editor::goto_visual_state (uint32_t n)
7696 if (visual_states.size() <= n) {
7700 if (visual_states[n] == 0) {
7704 use_visual_state (*visual_states[n]);
7708 Editor::start_visual_state_op (uint32_t n)
7710 save_visual_state (n);
7712 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7714 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7715 pup->set_text (buf);
7720 Editor::cancel_visual_state_op (uint32_t n)
7722 goto_visual_state (n);
7726 Editor::toggle_region_mute ()
7728 if (_ignore_region_action) {
7732 RegionSelection rs = get_regions_from_selection_and_entered ();
7738 if (rs.size() > 1) {
7739 begin_reversible_command (_("mute regions"));
7741 begin_reversible_command (_("mute region"));
7744 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7746 (*i)->region()->playlist()->clear_changes ();
7747 (*i)->region()->set_muted (!(*i)->region()->muted ());
7748 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7752 commit_reversible_command ();
7756 Editor::combine_regions ()
7758 /* foreach track with selected regions, take all selected regions
7759 and join them into a new region containing the subregions (as a
7763 typedef set<RouteTimeAxisView*> RTVS;
7766 if (selection->regions.empty()) {
7770 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7771 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7774 tracks.insert (rtv);
7778 begin_reversible_command (_("combine regions"));
7780 vector<RegionView*> new_selection;
7782 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7785 if ((rv = (*i)->combine_regions ()) != 0) {
7786 new_selection.push_back (rv);
7790 selection->clear_regions ();
7791 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7792 selection->add (*i);
7795 commit_reversible_command ();
7799 Editor::uncombine_regions ()
7801 typedef set<RouteTimeAxisView*> RTVS;
7804 if (selection->regions.empty()) {
7808 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7809 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7812 tracks.insert (rtv);
7816 begin_reversible_command (_("uncombine regions"));
7818 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7819 (*i)->uncombine_regions ();
7822 commit_reversible_command ();
7826 Editor::toggle_midi_input_active (bool flip_others)
7829 boost::shared_ptr<RouteList> rl (new RouteList);
7831 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7832 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7838 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7841 rl->push_back (rtav->route());
7842 onoff = !mt->input_active();
7846 _session->set_exclusive_input_active (rl, onoff, flip_others);
7853 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7855 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7856 lock_dialog->get_vbox()->pack_start (*padlock);
7858 ArdourButton* b = manage (new ArdourButton);
7859 b->set_name ("lock button");
7860 b->set_text (_("Click to unlock"));
7861 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7862 lock_dialog->get_vbox()->pack_start (*b);
7864 lock_dialog->get_vbox()->show_all ();
7865 lock_dialog->set_size_request (200, 200);
7868 delete _main_menu_disabler;
7869 _main_menu_disabler = new MainMenuDisabler;
7871 lock_dialog->present ();
7877 lock_dialog->hide ();
7879 delete _main_menu_disabler;
7880 _main_menu_disabler = 0;
7882 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7883 start_lock_event_timing ();
7888 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7890 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7894 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7896 Timers::TimerSuspender t;
7897 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7898 Gtkmm2ext::UI::instance()->flush_pending ();
7902 Editor::bring_all_sources_into_session ()
7909 ArdourDialog w (_("Moving embedded files into session folder"));
7910 w.get_vbox()->pack_start (msg);
7913 /* flush all pending GUI events because we're about to start copying
7917 Timers::TimerSuspender t;
7918 Gtkmm2ext::UI::instance()->flush_pending ();
7922 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));