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);
1593 Editor::scroll_left_step ()
1595 framepos_t xdelta = (current_page_samples() / 8);
1597 if (leftmost_frame > xdelta) {
1598 reset_x_origin (leftmost_frame - xdelta);
1606 Editor::scroll_right_step ()
1608 framepos_t xdelta = (current_page_samples() / 8);
1610 if (max_framepos - xdelta > leftmost_frame) {
1611 reset_x_origin (leftmost_frame + xdelta);
1613 reset_x_origin (max_framepos - current_page_samples());
1618 Editor::scroll_left_half_page ()
1620 framepos_t xdelta = (current_page_samples() / 2);
1621 if (leftmost_frame > xdelta) {
1622 reset_x_origin (leftmost_frame - xdelta);
1629 Editor::scroll_right_half_page ()
1631 framepos_t xdelta = (current_page_samples() / 2);
1632 if (max_framepos - xdelta > leftmost_frame) {
1633 reset_x_origin (leftmost_frame + xdelta);
1635 reset_x_origin (max_framepos - current_page_samples());
1642 Editor::tav_zoom_step (bool coarser)
1644 DisplaySuspender ds;
1648 if (selection->tracks.empty()) {
1651 ts = &selection->tracks;
1654 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1655 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1656 tv->step_height (coarser);
1661 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1663 DisplaySuspender ds;
1667 if (selection->tracks.empty() || force_all) {
1670 ts = &selection->tracks;
1673 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1674 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1675 uint32_t h = tv->current_height ();
1680 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1685 tv->set_height (h + 5);
1691 Editor::temporal_zoom_step_mouse_focus (bool coarser)
1693 Editing::ZoomFocus temp_focus = zoom_focus;
1694 zoom_focus = Editing::ZoomFocusMouse;
1695 temporal_zoom_step (coarser);
1696 zoom_focus = temp_focus;
1700 Editor::temporal_zoom_step (bool coarser)
1702 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1704 framecnt_t nspp = samples_per_pixel;
1712 temporal_zoom (nspp);
1716 Editor::temporal_zoom (framecnt_t fpp)
1722 framepos_t current_page = current_page_samples();
1723 framepos_t current_leftmost = leftmost_frame;
1724 framepos_t current_rightmost;
1725 framepos_t current_center;
1726 framepos_t new_page_size;
1727 framepos_t half_page_size;
1728 framepos_t leftmost_after_zoom = 0;
1730 bool in_track_canvas;
1734 if (fpp == samples_per_pixel) {
1738 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1739 // segfaults for lack of memory. If somebody decides this is not high enough I
1740 // believe it can be raisen to higher values but some limit must be in place.
1742 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1743 // all of which is used for the editor track displays. The whole day
1744 // would be 4147200000 samples, so 2592000 samples per pixel.
1746 nfpp = min (fpp, (framecnt_t) 2592000);
1747 nfpp = max ((framecnt_t) 1, nfpp);
1749 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1750 half_page_size = new_page_size / 2;
1752 switch (zoom_focus) {
1754 leftmost_after_zoom = current_leftmost;
1757 case ZoomFocusRight:
1758 current_rightmost = leftmost_frame + current_page;
1759 if (current_rightmost < new_page_size) {
1760 leftmost_after_zoom = 0;
1762 leftmost_after_zoom = current_rightmost - new_page_size;
1766 case ZoomFocusCenter:
1767 current_center = current_leftmost + (current_page/2);
1768 if (current_center < half_page_size) {
1769 leftmost_after_zoom = 0;
1771 leftmost_after_zoom = current_center - half_page_size;
1775 case ZoomFocusPlayhead:
1776 /* centre playhead */
1777 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1780 leftmost_after_zoom = 0;
1781 } else if (l > max_framepos) {
1782 leftmost_after_zoom = max_framepos - new_page_size;
1784 leftmost_after_zoom = (framepos_t) l;
1788 case ZoomFocusMouse:
1789 /* try to keep the mouse over the same point in the display */
1791 if (!mouse_frame (where, in_track_canvas)) {
1792 /* use playhead instead */
1793 where = playhead_cursor->current_frame ();
1795 if (where < half_page_size) {
1796 leftmost_after_zoom = 0;
1798 leftmost_after_zoom = where - half_page_size;
1803 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1806 leftmost_after_zoom = 0;
1807 } else if (l > max_framepos) {
1808 leftmost_after_zoom = max_framepos - new_page_size;
1810 leftmost_after_zoom = (framepos_t) l;
1817 /* try to keep the edit point in the same place */
1818 where = get_preferred_edit_position ();
1822 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1825 leftmost_after_zoom = 0;
1826 } else if (l > max_framepos) {
1827 leftmost_after_zoom = max_framepos - new_page_size;
1829 leftmost_after_zoom = (framepos_t) l;
1833 /* edit point not defined */
1840 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1842 reposition_and_zoom (leftmost_after_zoom, nfpp);
1846 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1848 /* this func helps make sure we leave a little space
1849 at each end of the editor so that the zoom doesn't fit the region
1850 precisely to the screen.
1853 GdkScreen* screen = gdk_screen_get_default ();
1854 const gint pixwidth = gdk_screen_get_width (screen);
1855 const gint mmwidth = gdk_screen_get_width_mm (screen);
1856 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1857 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1859 const framepos_t range = end - start;
1860 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1861 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1863 if (start > extra_samples) {
1864 start -= extra_samples;
1869 if (max_framepos - extra_samples > end) {
1870 end += extra_samples;
1877 Editor::temporal_zoom_region (bool both_axes)
1879 framepos_t start = max_framepos;
1881 set<TimeAxisView*> tracks;
1883 if ( !get_selection_extents(start, end) )
1886 calc_extra_zoom_edges (start, end);
1888 /* if we're zooming on both axes we need to save track heights etc.
1891 undo_visual_stack.push_back (current_visual_state (both_axes));
1893 PBD::Unwinder<bool> nsv (no_save_visual, true);
1895 temporal_zoom_by_frame (start, end);
1898 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1900 /* set visible track heights appropriately */
1902 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1903 (*t)->set_height (per_track_height);
1906 /* hide irrelevant tracks */
1908 DisplaySuspender ds;
1910 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1911 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1912 hide_track_in_display (*i);
1916 vertical_adjustment.set_value (0.0);
1919 redo_visual_stack.push_back (current_visual_state (both_axes));
1924 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1926 start = max_framepos;
1930 //ToDo: if notes are selected, set extents to that selection
1932 //ToDo: if control points are selected, set extents to that selection
1934 if ( !selection->regions.empty() ) {
1935 RegionSelection rs = get_regions_from_selection_and_entered ();
1937 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1939 if ((*i)->region()->position() < start) {
1940 start = (*i)->region()->position();
1943 if ((*i)->region()->last_frame() + 1 > end) {
1944 end = (*i)->region()->last_frame() + 1;
1948 } else if (!selection->time.empty()) {
1949 start = selection->time.start();
1950 end = selection->time.end_frame();
1952 ret = false; //no selection found
1955 if ((start == 0 && end == 0) || end < start) {
1964 Editor::temporal_zoom_selection (bool both_axes)
1966 if (!selection) return;
1968 //ToDo: if notes are selected, zoom to that
1970 //ToDo: if control points are selected, zoom to that
1972 //if region(s) are selected, zoom to that
1973 if ( !selection->regions.empty() )
1974 temporal_zoom_region (both_axes);
1976 //if a range is selected, zoom to that
1977 if (!selection->time.empty()) {
1979 framepos_t start, end;
1980 if (get_selection_extents (start, end)) {
1981 calc_extra_zoom_edges(start, end);
1982 temporal_zoom_by_frame (start, end);
1992 Editor::temporal_zoom_session ()
1994 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1997 framecnt_t start = _session->current_start_frame();
1998 framecnt_t end = _session->current_end_frame();
2000 if (_session->actively_recording () ) {
2001 framepos_t cur = playhead_cursor->current_frame ();
2003 /* recording beyond the end marker; zoom out
2004 * by 5 seconds more so that if 'follow
2005 * playhead' is active we don't immediately
2008 end = cur + _session->frame_rate() * 5;
2012 if ((start == 0 && end == 0) || end < start) {
2016 calc_extra_zoom_edges(start, end);
2018 temporal_zoom_by_frame (start, end);
2023 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2025 if (!_session) return;
2027 if ((start == 0 && end == 0) || end < start) {
2031 framepos_t range = end - start;
2033 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2035 framepos_t new_page = range;
2036 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2037 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2039 if (new_leftmost > middle) {
2043 if (new_leftmost < 0) {
2047 reposition_and_zoom (new_leftmost, new_fpp);
2051 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2057 framecnt_t range_before = frame - leftmost_frame;
2061 if (samples_per_pixel <= 1) {
2064 new_spp = samples_per_pixel + (samples_per_pixel/2);
2066 range_before += range_before/2;
2068 if (samples_per_pixel >= 1) {
2069 new_spp = samples_per_pixel - (samples_per_pixel/2);
2071 /* could bail out here since we cannot zoom any finer,
2072 but leave that to the equality test below
2074 new_spp = samples_per_pixel;
2077 range_before -= range_before/2;
2080 if (new_spp == samples_per_pixel) {
2084 /* zoom focus is automatically taken as @param frame when this
2088 framepos_t new_leftmost = frame - (framepos_t)range_before;
2090 if (new_leftmost > frame) {
2094 if (new_leftmost < 0) {
2098 reposition_and_zoom (new_leftmost, new_spp);
2103 Editor::choose_new_marker_name(string &name) {
2105 if (!UIConfiguration::instance().get_name_new_markers()) {
2106 /* don't prompt user for a new name */
2110 ArdourPrompter dialog (true);
2112 dialog.set_prompt (_("New Name:"));
2114 dialog.set_title (_("New Location Marker"));
2116 dialog.set_name ("MarkNameWindow");
2117 dialog.set_size_request (250, -1);
2118 dialog.set_position (Gtk::WIN_POS_MOUSE);
2120 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2121 dialog.set_initial_text (name);
2125 switch (dialog.run ()) {
2126 case RESPONSE_ACCEPT:
2132 dialog.get_result(name);
2139 Editor::add_location_from_selection ()
2143 if (selection->time.empty()) {
2147 if (_session == 0 || clicked_axisview == 0) {
2151 framepos_t start = selection->time[clicked_selection].start;
2152 framepos_t end = selection->time[clicked_selection].end;
2154 _session->locations()->next_available_name(rangename,"selection");
2155 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2157 begin_reversible_command (_("add marker"));
2159 XMLNode &before = _session->locations()->get_state();
2160 _session->locations()->add (location, true);
2161 XMLNode &after = _session->locations()->get_state();
2162 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2164 commit_reversible_command ();
2168 Editor::add_location_mark (framepos_t where)
2172 select_new_marker = true;
2174 _session->locations()->next_available_name(markername,"mark");
2175 if (!choose_new_marker_name(markername)) {
2178 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2179 begin_reversible_command (_("add marker"));
2181 XMLNode &before = _session->locations()->get_state();
2182 _session->locations()->add (location, true);
2183 XMLNode &after = _session->locations()->get_state();
2184 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2186 commit_reversible_command ();
2190 Editor::set_session_start_from_playhead ()
2196 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2197 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2199 XMLNode &before = loc->get_state();
2201 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2203 XMLNode &after = loc->get_state();
2205 begin_reversible_command (_("Set session start"));
2207 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2209 commit_reversible_command ();
2214 Editor::set_session_end_from_playhead ()
2220 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2221 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2223 XMLNode &before = loc->get_state();
2225 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2227 XMLNode &after = loc->get_state();
2229 begin_reversible_command (_("Set session start"));
2231 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2233 commit_reversible_command ();
2238 Editor::add_location_from_playhead_cursor ()
2240 add_location_mark (_session->audible_frame());
2244 Editor::remove_location_at_playhead_cursor ()
2248 XMLNode &before = _session->locations()->get_state();
2249 bool removed = false;
2251 //find location(s) at this time
2252 Locations::LocationList locs;
2253 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2254 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2255 if ((*i)->is_mark()) {
2256 _session->locations()->remove (*i);
2263 begin_reversible_command (_("remove marker"));
2264 XMLNode &after = _session->locations()->get_state();
2265 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2266 commit_reversible_command ();
2271 /** Add a range marker around each selected region */
2273 Editor::add_locations_from_region ()
2275 RegionSelection rs = get_regions_from_selection_and_entered ();
2280 bool commit = false;
2282 XMLNode &before = _session->locations()->get_state();
2284 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2286 boost::shared_ptr<Region> region = (*i)->region ();
2288 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2290 _session->locations()->add (location, true);
2295 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2296 XMLNode &after = _session->locations()->get_state();
2297 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2298 commit_reversible_command ();
2302 /** Add a single range marker around all selected regions */
2304 Editor::add_location_from_region ()
2306 RegionSelection rs = get_regions_from_selection_and_entered ();
2312 XMLNode &before = _session->locations()->get_state();
2316 if (rs.size() > 1) {
2317 _session->locations()->next_available_name(markername, "regions");
2319 RegionView* rv = *(rs.begin());
2320 boost::shared_ptr<Region> region = rv->region();
2321 markername = region->name();
2324 if (!choose_new_marker_name(markername)) {
2328 // single range spanning all selected
2329 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2330 _session->locations()->add (location, true);
2332 begin_reversible_command (_("add marker"));
2333 XMLNode &after = _session->locations()->get_state();
2334 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2335 commit_reversible_command ();
2341 Editor::jump_forward_to_mark ()
2347 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2353 _session->request_locate (pos, _session->transport_rolling());
2357 Editor::jump_backward_to_mark ()
2363 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2369 _session->request_locate (pos, _session->transport_rolling());
2375 framepos_t const pos = _session->audible_frame ();
2378 _session->locations()->next_available_name (markername, "mark");
2380 if (!choose_new_marker_name (markername)) {
2384 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2388 Editor::clear_markers ()
2391 begin_reversible_command (_("clear markers"));
2393 XMLNode &before = _session->locations()->get_state();
2394 _session->locations()->clear_markers ();
2395 XMLNode &after = _session->locations()->get_state();
2396 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2398 commit_reversible_command ();
2403 Editor::clear_ranges ()
2406 begin_reversible_command (_("clear ranges"));
2408 XMLNode &before = _session->locations()->get_state();
2410 _session->locations()->clear_ranges ();
2412 XMLNode &after = _session->locations()->get_state();
2413 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2415 commit_reversible_command ();
2420 Editor::clear_locations ()
2422 begin_reversible_command (_("clear locations"));
2424 XMLNode &before = _session->locations()->get_state();
2425 _session->locations()->clear ();
2426 XMLNode &after = _session->locations()->get_state();
2427 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2429 commit_reversible_command ();
2433 Editor::unhide_markers ()
2435 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2436 Location *l = (*i).first;
2437 if (l->is_hidden() && l->is_mark()) {
2438 l->set_hidden(false, this);
2444 Editor::unhide_ranges ()
2446 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2447 Location *l = (*i).first;
2448 if (l->is_hidden() && l->is_range_marker()) {
2449 l->set_hidden(false, this);
2454 /* INSERT/REPLACE */
2457 Editor::insert_region_list_selection (float times)
2459 RouteTimeAxisView *tv = 0;
2460 boost::shared_ptr<Playlist> playlist;
2462 if (clicked_routeview != 0) {
2463 tv = clicked_routeview;
2464 } else if (!selection->tracks.empty()) {
2465 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2468 } else if (entered_track != 0) {
2469 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2476 if ((playlist = tv->playlist()) == 0) {
2480 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2485 begin_reversible_command (_("insert region"));
2486 playlist->clear_changes ();
2487 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2488 if (Config->get_edit_mode() == Ripple)
2489 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2491 _session->add_command(new StatefulDiffCommand (playlist));
2492 commit_reversible_command ();
2495 /* BUILT-IN EFFECTS */
2498 Editor::reverse_selection ()
2503 /* GAIN ENVELOPE EDITING */
2506 Editor::edit_envelope ()
2513 Editor::transition_to_rolling (bool fwd)
2519 if (_session->config.get_external_sync()) {
2520 switch (Config->get_sync_source()) {
2524 /* transport controlled by the master */
2529 if (_session->is_auditioning()) {
2530 _session->cancel_audition ();
2534 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2538 Editor::play_from_start ()
2540 _session->request_locate (_session->current_start_frame(), true);
2544 Editor::play_from_edit_point ()
2546 _session->request_locate (get_preferred_edit_position(), true);
2550 Editor::play_from_edit_point_and_return ()
2552 framepos_t start_frame;
2553 framepos_t return_frame;
2555 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2557 if (_session->transport_rolling()) {
2558 _session->request_locate (start_frame, false);
2562 /* don't reset the return frame if its already set */
2564 if ((return_frame = _session->requested_return_frame()) < 0) {
2565 return_frame = _session->audible_frame();
2568 if (start_frame >= 0) {
2569 _session->request_roll_at_and_return (start_frame, return_frame);
2574 Editor::play_selection ()
2576 framepos_t start, end;
2577 if (!get_selection_extents ( start, end))
2580 AudioRange ar (start, end, 0);
2581 list<AudioRange> lar;
2584 _session->request_play_range (&lar, true);
2588 Editor::get_preroll ()
2590 return Config->get_preroll_seconds() * _session->frame_rate();
2595 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2597 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2600 location -= get_preroll();
2602 //don't try to locate before the beginning of time
2606 //if follow_playhead is on, keep the playhead on the screen
2607 if ( _follow_playhead )
2608 if ( location < leftmost_frame )
2609 location = leftmost_frame;
2611 _session->request_locate( location );
2615 Editor::play_with_preroll ()
2618 framepos_t preroll = get_preroll();
2620 framepos_t start, end;
2621 if (!get_selection_extents ( start, end))
2624 if (start > preroll)
2625 start = start - preroll;
2627 end = end + preroll; //"post-roll"
2629 AudioRange ar (start, end, 0);
2630 list<AudioRange> lar;
2633 _session->request_play_range (&lar, true);
2638 Editor::play_location (Location& location)
2640 if (location.start() <= location.end()) {
2644 _session->request_bounded_roll (location.start(), location.end());
2648 Editor::loop_location (Location& location)
2650 if (location.start() <= location.end()) {
2656 if ((tll = transport_loop_location()) != 0) {
2657 tll->set (location.start(), location.end());
2659 // enable looping, reposition and start rolling
2660 _session->request_locate (tll->start(), true);
2661 _session->request_play_loop (true);
2666 Editor::do_layer_operation (LayerOperation op)
2668 if (selection->regions.empty ()) {
2672 bool const multiple = selection->regions.size() > 1;
2676 begin_reversible_command (_("raise regions"));
2678 begin_reversible_command (_("raise region"));
2684 begin_reversible_command (_("raise regions to top"));
2686 begin_reversible_command (_("raise region to top"));
2692 begin_reversible_command (_("lower regions"));
2694 begin_reversible_command (_("lower region"));
2700 begin_reversible_command (_("lower regions to bottom"));
2702 begin_reversible_command (_("lower region"));
2707 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2708 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2709 (*i)->clear_owned_changes ();
2712 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2713 boost::shared_ptr<Region> r = (*i)->region ();
2725 r->lower_to_bottom ();
2729 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2730 vector<Command*> cmds;
2732 _session->add_commands (cmds);
2735 commit_reversible_command ();
2739 Editor::raise_region ()
2741 do_layer_operation (Raise);
2745 Editor::raise_region_to_top ()
2747 do_layer_operation (RaiseToTop);
2751 Editor::lower_region ()
2753 do_layer_operation (Lower);
2757 Editor::lower_region_to_bottom ()
2759 do_layer_operation (LowerToBottom);
2762 /** Show the region editor for the selected regions */
2764 Editor::show_region_properties ()
2766 selection->foreach_regionview (&RegionView::show_region_editor);
2769 /** Show the midi list editor for the selected MIDI regions */
2771 Editor::show_midi_list_editor ()
2773 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2777 Editor::rename_region ()
2779 RegionSelection rs = get_regions_from_selection_and_entered ();
2785 ArdourDialog d (_("Rename Region"), true, false);
2787 Label label (_("New name:"));
2790 hbox.set_spacing (6);
2791 hbox.pack_start (label, false, false);
2792 hbox.pack_start (entry, true, true);
2794 d.get_vbox()->set_border_width (12);
2795 d.get_vbox()->pack_start (hbox, false, false);
2797 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2798 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2800 d.set_size_request (300, -1);
2802 entry.set_text (rs.front()->region()->name());
2803 entry.select_region (0, -1);
2805 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2811 int const ret = d.run();
2815 if (ret != RESPONSE_OK) {
2819 std::string str = entry.get_text();
2820 strip_whitespace_edges (str);
2822 rs.front()->region()->set_name (str);
2823 _regions->redisplay ();
2827 /** Start an audition of the first selected region */
2829 Editor::play_edit_range ()
2831 framepos_t start, end;
2833 if (get_edit_op_range (start, end)) {
2834 _session->request_bounded_roll (start, end);
2839 Editor::play_selected_region ()
2841 framepos_t start = max_framepos;
2844 RegionSelection rs = get_regions_from_selection_and_entered ();
2850 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2851 if ((*i)->region()->position() < start) {
2852 start = (*i)->region()->position();
2854 if ((*i)->region()->last_frame() + 1 > end) {
2855 end = (*i)->region()->last_frame() + 1;
2859 _session->request_bounded_roll (start, end);
2863 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2865 _session->audition_region (region);
2869 Editor::region_from_selection ()
2871 if (clicked_axisview == 0) {
2875 if (selection->time.empty()) {
2879 framepos_t start = selection->time[clicked_selection].start;
2880 framepos_t end = selection->time[clicked_selection].end;
2882 TrackViewList tracks = get_tracks_for_range_action ();
2884 framepos_t selection_cnt = end - start + 1;
2886 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2887 boost::shared_ptr<Region> current;
2888 boost::shared_ptr<Playlist> pl;
2889 framepos_t internal_start;
2892 if ((pl = (*i)->playlist()) == 0) {
2896 if ((current = pl->top_region_at (start)) == 0) {
2900 internal_start = start - current->position();
2901 RegionFactory::region_name (new_name, current->name(), true);
2905 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2906 plist.add (ARDOUR::Properties::length, selection_cnt);
2907 plist.add (ARDOUR::Properties::name, new_name);
2908 plist.add (ARDOUR::Properties::layer, 0);
2910 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2915 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2917 if (selection->time.empty() || selection->tracks.empty()) {
2921 framepos_t start, end;
2922 if (clicked_selection) {
2923 start = selection->time[clicked_selection].start;
2924 end = selection->time[clicked_selection].end;
2926 start = selection->time.start();
2927 end = selection->time.end_frame();
2930 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2931 sort_track_selection (ts);
2933 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2934 boost::shared_ptr<Region> current;
2935 boost::shared_ptr<Playlist> playlist;
2936 framepos_t internal_start;
2939 if ((playlist = (*i)->playlist()) == 0) {
2943 if ((current = playlist->top_region_at(start)) == 0) {
2947 internal_start = start - current->position();
2948 RegionFactory::region_name (new_name, current->name(), true);
2952 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2953 plist.add (ARDOUR::Properties::length, end - start + 1);
2954 plist.add (ARDOUR::Properties::name, new_name);
2956 new_regions.push_back (RegionFactory::create (current, plist));
2961 Editor::split_multichannel_region ()
2963 RegionSelection rs = get_regions_from_selection_and_entered ();
2969 vector< boost::shared_ptr<Region> > v;
2971 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2972 (*x)->region()->separate_by_channel (*_session, v);
2977 Editor::new_region_from_selection ()
2979 region_from_selection ();
2980 cancel_selection ();
2984 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2986 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2987 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2988 case Evoral::OverlapNone:
2996 * - selected tracks, or if there are none...
2997 * - tracks containing selected regions, or if there are none...
3002 Editor::get_tracks_for_range_action () const
3006 if (selection->tracks.empty()) {
3008 /* use tracks with selected regions */
3010 RegionSelection rs = selection->regions;
3012 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3013 TimeAxisView* tv = &(*i)->get_time_axis_view();
3015 if (!t.contains (tv)) {
3021 /* no regions and no tracks: use all tracks */
3027 t = selection->tracks;
3030 return t.filter_to_unique_playlists();
3034 Editor::separate_regions_between (const TimeSelection& ts)
3036 bool in_command = false;
3037 boost::shared_ptr<Playlist> playlist;
3038 RegionSelection new_selection;
3040 TrackViewList tmptracks = get_tracks_for_range_action ();
3041 sort_track_selection (tmptracks);
3043 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3045 RouteTimeAxisView* rtv;
3047 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3049 if (rtv->is_track()) {
3051 /* no edits to destructive tracks */
3053 if (rtv->track()->destructive()) {
3057 if ((playlist = rtv->playlist()) != 0) {
3059 playlist->clear_changes ();
3061 /* XXX need to consider musical time selections here at some point */
3063 double speed = rtv->track()->speed();
3066 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3068 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3069 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3071 latest_regionviews.clear ();
3073 playlist->partition ((framepos_t)((*t).start * speed),
3074 (framepos_t)((*t).end * speed), false);
3078 if (!latest_regionviews.empty()) {
3080 rtv->view()->foreach_regionview (sigc::bind (
3081 sigc::ptr_fun (add_if_covered),
3082 &(*t), &new_selection));
3085 begin_reversible_command (_("separate"));
3089 /* pick up changes to existing regions */
3091 vector<Command*> cmds;
3092 playlist->rdiff (cmds);
3093 _session->add_commands (cmds);
3095 /* pick up changes to the playlist itself (adds/removes)
3098 _session->add_command(new StatefulDiffCommand (playlist));
3107 // selection->set (new_selection);
3109 commit_reversible_command ();
3113 struct PlaylistState {
3114 boost::shared_ptr<Playlist> playlist;
3118 /** Take tracks from get_tracks_for_range_action and cut any regions
3119 * on those tracks so that the tracks are empty over the time
3123 Editor::separate_region_from_selection ()
3125 /* preferentially use *all* ranges in the time selection if we're in range mode
3126 to allow discontiguous operation, since get_edit_op_range() currently
3127 returns a single range.
3130 if (!selection->time.empty()) {
3132 separate_regions_between (selection->time);
3139 if (get_edit_op_range (start, end)) {
3141 AudioRange ar (start, end, 1);
3145 separate_regions_between (ts);
3151 Editor::separate_region_from_punch ()
3153 Location* loc = _session->locations()->auto_punch_location();
3155 separate_regions_using_location (*loc);
3160 Editor::separate_region_from_loop ()
3162 Location* loc = _session->locations()->auto_loop_location();
3164 separate_regions_using_location (*loc);
3169 Editor::separate_regions_using_location (Location& loc)
3171 if (loc.is_mark()) {
3175 AudioRange ar (loc.start(), loc.end(), 1);
3180 separate_regions_between (ts);
3183 /** Separate regions under the selected region */
3185 Editor::separate_under_selected_regions ()
3187 vector<PlaylistState> playlists;
3191 rs = get_regions_from_selection_and_entered();
3193 if (!_session || rs.empty()) {
3197 begin_reversible_command (_("separate region under"));
3199 list<boost::shared_ptr<Region> > regions_to_remove;
3201 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3202 // we can't just remove the region(s) in this loop because
3203 // this removes them from the RegionSelection, and they thus
3204 // disappear from underneath the iterator, and the ++i above
3205 // SEGVs in a puzzling fashion.
3207 // so, first iterate over the regions to be removed from rs and
3208 // add them to the regions_to_remove list, and then
3209 // iterate over the list to actually remove them.
3211 regions_to_remove.push_back ((*i)->region());
3214 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3216 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3219 // is this check necessary?
3223 vector<PlaylistState>::iterator i;
3225 //only take state if this is a new playlist.
3226 for (i = playlists.begin(); i != playlists.end(); ++i) {
3227 if ((*i).playlist == playlist) {
3232 if (i == playlists.end()) {
3234 PlaylistState before;
3235 before.playlist = playlist;
3236 before.before = &playlist->get_state();
3238 playlist->freeze ();
3239 playlists.push_back(before);
3242 //Partition on the region bounds
3243 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3245 //Re-add region that was just removed due to the partition operation
3246 playlist->add_region( (*rl), (*rl)->first_frame() );
3249 vector<PlaylistState>::iterator pl;
3251 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3252 (*pl).playlist->thaw ();
3253 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3256 commit_reversible_command ();
3260 Editor::crop_region_to_selection ()
3262 if (!selection->time.empty()) {
3264 crop_region_to (selection->time.start(), selection->time.end_frame());
3271 if (get_edit_op_range (start, end)) {
3272 crop_region_to (start, end);
3279 Editor::crop_region_to (framepos_t start, framepos_t end)
3281 vector<boost::shared_ptr<Playlist> > playlists;
3282 boost::shared_ptr<Playlist> playlist;
3285 if (selection->tracks.empty()) {
3286 ts = track_views.filter_to_unique_playlists();
3288 ts = selection->tracks.filter_to_unique_playlists ();
3291 sort_track_selection (ts);
3293 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3295 RouteTimeAxisView* rtv;
3297 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3299 boost::shared_ptr<Track> t = rtv->track();
3301 if (t != 0 && ! t->destructive()) {
3303 if ((playlist = rtv->playlist()) != 0) {
3304 playlists.push_back (playlist);
3310 if (playlists.empty()) {
3315 framepos_t new_start;
3317 framecnt_t new_length;
3318 bool in_command = false;
3320 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3322 /* Only the top regions at start and end have to be cropped */
3323 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3324 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3326 vector<boost::shared_ptr<Region> > regions;
3328 if (region_at_start != 0) {
3329 regions.push_back (region_at_start);
3331 if (region_at_end != 0) {
3332 regions.push_back (region_at_end);
3335 /* now adjust lengths */
3336 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3338 pos = (*i)->position();
3339 new_start = max (start, pos);
3340 if (max_framepos - pos > (*i)->length()) {
3341 new_end = pos + (*i)->length() - 1;
3343 new_end = max_framepos;
3345 new_end = min (end, new_end);
3346 new_length = new_end - new_start + 1;
3349 begin_reversible_command (_("trim to selection"));
3352 (*i)->clear_changes ();
3353 (*i)->trim_to (new_start, new_length);
3354 _session->add_command (new StatefulDiffCommand (*i));
3359 commit_reversible_command ();
3364 Editor::region_fill_track ()
3366 boost::shared_ptr<Playlist> playlist;
3367 RegionSelection regions = get_regions_from_selection_and_entered ();
3368 RegionSelection foo;
3370 framepos_t const end = _session->current_end_frame ();
3372 if (regions.empty () || regions.end_frame () + 1 >= end) {
3376 framepos_t const start_frame = regions.start ();
3377 framepos_t const end_frame = regions.end_frame ();
3378 framecnt_t const gap = end_frame - start_frame + 1;
3380 begin_reversible_command (Operations::region_fill);
3382 selection->clear_regions ();
3384 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3386 boost::shared_ptr<Region> r ((*i)->region());
3388 TimeAxisView& tv = (*i)->get_time_axis_view();
3389 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3390 latest_regionviews.clear ();
3391 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3393 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3394 playlist = (*i)->region()->playlist();
3395 playlist->clear_changes ();
3396 playlist->duplicate_until (r, position, gap, end);
3397 _session->add_command(new StatefulDiffCommand (playlist));
3401 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3405 selection->set (foo);
3408 commit_reversible_command ();
3412 Editor::set_region_sync_position ()
3414 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3418 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3420 bool in_command = false;
3422 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3424 if (!(*r)->region()->covers (where)) {
3428 boost::shared_ptr<Region> region ((*r)->region());
3431 begin_reversible_command (_("set sync point"));
3435 region->clear_changes ();
3436 region->set_sync_position (where);
3437 _session->add_command(new StatefulDiffCommand (region));
3441 commit_reversible_command ();
3445 /** Remove the sync positions of the selection */
3447 Editor::remove_region_sync ()
3449 RegionSelection rs = get_regions_from_selection_and_entered ();
3455 begin_reversible_command (_("remove region sync"));
3457 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3459 (*i)->region()->clear_changes ();
3460 (*i)->region()->clear_sync_position ();
3461 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3464 commit_reversible_command ();
3468 Editor::naturalize_region ()
3470 RegionSelection rs = get_regions_from_selection_and_entered ();
3476 if (rs.size() > 1) {
3477 begin_reversible_command (_("move regions to original position"));
3479 begin_reversible_command (_("move region to original position"));
3482 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3483 (*i)->region()->clear_changes ();
3484 (*i)->region()->move_to_natural_position ();
3485 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3488 commit_reversible_command ();
3492 Editor::align_regions (RegionPoint what)
3494 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3500 begin_reversible_command (_("align selection"));
3502 framepos_t const position = get_preferred_edit_position ();
3504 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3505 align_region_internal ((*i)->region(), what, position);
3508 commit_reversible_command ();
3511 struct RegionSortByTime {
3512 bool operator() (const RegionView* a, const RegionView* b) {
3513 return a->region()->position() < b->region()->position();
3518 Editor::align_regions_relative (RegionPoint point)
3520 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3526 framepos_t const position = get_preferred_edit_position ();
3528 framepos_t distance = 0;
3532 list<RegionView*> sorted;
3533 rs.by_position (sorted);
3535 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3540 if (position > r->position()) {
3541 distance = position - r->position();
3543 distance = r->position() - position;
3549 if (position > r->last_frame()) {
3550 distance = position - r->last_frame();
3551 pos = r->position() + distance;
3553 distance = r->last_frame() - position;
3554 pos = r->position() - distance;
3560 pos = r->adjust_to_sync (position);
3561 if (pos > r->position()) {
3562 distance = pos - r->position();
3564 distance = r->position() - pos;
3570 if (pos == r->position()) {
3574 begin_reversible_command (_("align selection (relative)"));
3576 /* move first one specially */
3578 r->clear_changes ();
3579 r->set_position (pos);
3580 _session->add_command(new StatefulDiffCommand (r));
3582 /* move rest by the same amount */
3586 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3588 boost::shared_ptr<Region> region ((*i)->region());
3590 region->clear_changes ();
3593 region->set_position (region->position() + distance);
3595 region->set_position (region->position() - distance);
3598 _session->add_command(new StatefulDiffCommand (region));
3602 commit_reversible_command ();
3606 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3608 begin_reversible_command (_("align region"));
3609 align_region_internal (region, point, position);
3610 commit_reversible_command ();
3614 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3616 region->clear_changes ();
3620 region->set_position (region->adjust_to_sync (position));
3624 if (position > region->length()) {
3625 region->set_position (position - region->length());
3630 region->set_position (position);
3634 _session->add_command(new StatefulDiffCommand (region));
3638 Editor::trim_region_front ()
3644 Editor::trim_region_back ()
3646 trim_region (false);
3650 Editor::trim_region (bool front)
3652 framepos_t where = get_preferred_edit_position();
3653 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3659 begin_reversible_command (front ? _("trim front") : _("trim back"));
3661 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3662 if (!(*i)->region()->locked()) {
3664 (*i)->region()->clear_changes ();
3667 (*i)->region()->trim_front (where);
3668 maybe_locate_with_edit_preroll ( where );
3670 (*i)->region()->trim_end (where);
3671 maybe_locate_with_edit_preroll ( where );
3674 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3678 commit_reversible_command ();
3681 /** Trim the end of the selected regions to the position of the edit cursor */
3683 Editor::trim_region_to_loop ()
3685 Location* loc = _session->locations()->auto_loop_location();
3689 trim_region_to_location (*loc, _("trim to loop"));
3693 Editor::trim_region_to_punch ()
3695 Location* loc = _session->locations()->auto_punch_location();
3699 trim_region_to_location (*loc, _("trim to punch"));
3703 Editor::trim_region_to_location (const Location& loc, const char* str)
3705 RegionSelection rs = get_regions_from_selection_and_entered ();
3706 bool in_command = false;
3708 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3709 RegionView* rv = (*x);
3711 /* require region to span proposed trim */
3712 switch (rv->region()->coverage (loc.start(), loc.end())) {
3713 case Evoral::OverlapInternal:
3719 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3728 if (tav->track() != 0) {
3729 speed = tav->track()->speed();
3732 start = session_frame_to_track_frame (loc.start(), speed);
3733 end = session_frame_to_track_frame (loc.end(), speed);
3735 rv->region()->clear_changes ();
3736 rv->region()->trim_to (start, (end - start));
3739 begin_reversible_command (str);
3742 _session->add_command(new StatefulDiffCommand (rv->region()));
3746 commit_reversible_command ();
3751 Editor::trim_region_to_previous_region_end ()
3753 return trim_to_region(false);
3757 Editor::trim_region_to_next_region_start ()
3759 return trim_to_region(true);
3763 Editor::trim_to_region(bool forward)
3765 RegionSelection rs = get_regions_from_selection_and_entered ();
3766 bool in_command = false;
3768 boost::shared_ptr<Region> next_region;
3770 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3772 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3778 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3786 if (atav->track() != 0) {
3787 speed = atav->track()->speed();
3791 boost::shared_ptr<Region> region = arv->region();
3792 boost::shared_ptr<Playlist> playlist (region->playlist());
3794 region->clear_changes ();
3798 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3804 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3805 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3809 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3815 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3817 arv->region_changed (ARDOUR::bounds_change);
3821 begin_reversible_command (_("trim to region"));
3824 _session->add_command(new StatefulDiffCommand (region));
3828 commit_reversible_command ();
3833 Editor::unfreeze_route ()
3835 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3839 clicked_routeview->track()->unfreeze ();
3843 Editor::_freeze_thread (void* arg)
3845 return static_cast<Editor*>(arg)->freeze_thread ();
3849 Editor::freeze_thread ()
3851 /* create event pool because we may need to talk to the session */
3852 SessionEvent::create_per_thread_pool ("freeze events", 64);
3853 /* create per-thread buffers for process() tree to use */
3854 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3855 current_interthread_info->done = true;
3860 Editor::freeze_route ()
3866 /* stop transport before we start. this is important */
3868 _session->request_transport_speed (0.0);
3870 /* wait for just a little while, because the above call is asynchronous */
3872 Glib::usleep (250000);
3874 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3878 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3880 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3881 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3883 d.set_title (_("Cannot freeze"));
3888 if (clicked_routeview->track()->has_external_redirects()) {
3889 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"
3890 "Freezing will only process the signal as far as the first send/insert/return."),
3891 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3893 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3894 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3895 d.set_title (_("Freeze Limits"));
3897 int response = d.run ();
3900 case Gtk::RESPONSE_CANCEL:
3907 InterThreadInfo itt;
3908 current_interthread_info = &itt;
3910 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3912 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3914 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3916 while (!itt.done && !itt.cancel) {
3917 gtk_main_iteration ();
3920 current_interthread_info = 0;
3924 Editor::bounce_range_selection (bool replace, bool enable_processing)
3926 if (selection->time.empty()) {
3930 TrackSelection views = selection->tracks;
3932 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3934 if (enable_processing) {
3936 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3938 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3940 _("You can't perform this operation because the processing of the signal "
3941 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3942 "You can do this without processing, which is a different operation.")
3944 d.set_title (_("Cannot bounce"));
3951 framepos_t start = selection->time[clicked_selection].start;
3952 framepos_t end = selection->time[clicked_selection].end;
3953 framepos_t cnt = end - start + 1;
3954 bool in_command = false;
3956 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3958 RouteTimeAxisView* rtv;
3960 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3964 boost::shared_ptr<Playlist> playlist;
3966 if ((playlist = rtv->playlist()) == 0) {
3970 InterThreadInfo itt;
3972 playlist->clear_changes ();
3973 playlist->clear_owned_changes ();
3975 boost::shared_ptr<Region> r;
3977 if (enable_processing) {
3978 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3980 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3988 list<AudioRange> ranges;
3989 ranges.push_back (AudioRange (start, start+cnt, 0));
3990 playlist->cut (ranges); // discard result
3991 playlist->add_region (r, start);
3995 begin_reversible_command (_("bounce range"));
3998 vector<Command*> cmds;
3999 playlist->rdiff (cmds);
4000 _session->add_commands (cmds);
4002 _session->add_command (new StatefulDiffCommand (playlist));
4006 commit_reversible_command ();
4010 /** Delete selected regions, automation points or a time range */
4014 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4015 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4016 bool deleted = false;
4017 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4018 deleted = current_mixer_strip->delete_processors ();
4024 /** Cut selected regions, automation points or a time range */
4031 /** Copy selected regions, automation points or a time range */
4039 /** @return true if a Cut, Copy or Clear is possible */
4041 Editor::can_cut_copy () const
4043 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4050 /** Cut, copy or clear selected regions, automation points or a time range.
4051 * @param op Operation (Delete, Cut, Copy or Clear)
4054 Editor::cut_copy (CutCopyOp op)
4056 /* only cancel selection if cut/copy is successful.*/
4062 opname = _("delete");
4071 opname = _("clear");
4075 /* if we're deleting something, and the mouse is still pressed,
4076 the thing we started a drag for will be gone when we release
4077 the mouse button(s). avoid this. see part 2 at the end of
4081 if (op == Delete || op == Cut || op == Clear) {
4082 if (_drags->active ()) {
4087 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4088 cut_buffer->clear ();
4090 if (entered_marker) {
4092 /* cut/delete op while pointing at a marker */
4095 Location* loc = find_location_from_marker (entered_marker, ignored);
4097 if (_session && loc) {
4098 entered_marker = NULL;
4099 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4106 switch (mouse_mode) {
4109 begin_reversible_command (opname + ' ' + X_("MIDI"));
4111 commit_reversible_command ();
4117 bool did_edit = false;
4119 if (!selection->regions.empty() || !selection->points.empty()) {
4120 begin_reversible_command (opname + ' ' + _("objects"));
4123 if (!selection->regions.empty()) {
4124 cut_copy_regions (op, selection->regions);
4126 if (op == Cut || op == Delete) {
4127 selection->clear_regions ();
4131 if (!selection->points.empty()) {
4132 cut_copy_points (op);
4134 if (op == Cut || op == Delete) {
4135 selection->clear_points ();
4138 } else if (selection->time.empty()) {
4139 framepos_t start, end;
4140 /* no time selection, see if we can get an edit range
4143 if (get_edit_op_range (start, end)) {
4144 selection->set (start, end);
4146 } else if (!selection->time.empty()) {
4147 begin_reversible_command (opname + ' ' + _("range"));
4150 cut_copy_ranges (op);
4152 if (op == Cut || op == Delete) {
4153 selection->clear_time ();
4158 /* reset repeated paste state */
4161 commit_reversible_command ();
4164 if (op == Delete || op == Cut || op == Clear) {
4169 struct AutomationRecord {
4170 AutomationRecord () : state (0) , line(NULL) {}
4171 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4173 XMLNode* state; ///< state before any operation
4174 const AutomationLine* line; ///< line this came from
4175 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4178 /** Cut, copy or clear selected automation points.
4179 * @param op Operation (Cut, Copy or Clear)
4182 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4184 if (selection->points.empty ()) {
4188 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4189 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4191 /* Keep a record of the AutomationLists that we end up using in this operation */
4192 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4195 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4196 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4197 const AutomationLine& line = (*i)->line();
4198 const boost::shared_ptr<AutomationList> al = line.the_list();
4199 if (lists.find (al) == lists.end ()) {
4200 /* We haven't seen this list yet, so make a record for it. This includes
4201 taking a copy of its current state, in case this is needed for undo later.
4203 lists[al] = AutomationRecord (&al->get_state (), &line);
4207 if (op == Cut || op == Copy) {
4208 /* This operation will involve putting things in the cut buffer, so create an empty
4209 ControlList for each of our source lists to put the cut buffer data in.
4211 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4212 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4215 /* Add all selected points to the relevant copy ControlLists */
4216 framepos_t start = std::numeric_limits<framepos_t>::max();
4217 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4218 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4219 AutomationList::const_iterator j = (*i)->model();
4221 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4223 /* Update earliest MIDI start time in beats */
4224 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4226 /* Update earliest session start time in frames */
4227 start = std::min(start, (*i)->line().session_position(j));
4231 /* Snap start time backwards, so copy/paste is snap aligned. */
4233 if (earliest == Evoral::Beats::max()) {
4234 earliest = Evoral::Beats(); // Weird... don't offset
4236 earliest.round_down_to_beat();
4238 if (start == std::numeric_limits<double>::max()) {
4239 start = 0; // Weird... don't offset
4241 snap_to(start, RoundDownMaybe);
4244 const double line_offset = midi ? earliest.to_double() : start;
4245 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4246 /* Correct this copy list so that it is relative to the earliest
4247 start time, so relative ordering between points is preserved
4248 when copying from several lists and the paste starts at the
4249 earliest copied piece of data. */
4250 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4251 (*j)->when -= line_offset;
4254 /* And add it to the cut buffer */
4255 cut_buffer->add (i->second.copy);
4259 if (op == Delete || op == Cut) {
4260 /* This operation needs to remove things from the main AutomationList, so do that now */
4262 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4263 i->first->freeze ();
4266 /* Remove each selected point from its AutomationList */
4267 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4268 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4269 al->erase ((*i)->model ());
4272 /* Thaw the lists and add undo records for them */
4273 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4274 boost::shared_ptr<AutomationList> al = i->first;
4276 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4281 /** Cut, copy or clear selected automation points.
4282 * @param op Operation (Cut, Copy or Clear)
4285 Editor::cut_copy_midi (CutCopyOp op)
4287 Evoral::Beats earliest = Evoral::Beats::max();
4288 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4289 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4291 if (!mrv->selection().empty()) {
4292 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4294 mrv->cut_copy_clear (op);
4296 /* XXX: not ideal, as there may be more than one track involved in the selection */
4297 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4301 if (!selection->points.empty()) {
4302 cut_copy_points (op, earliest, true);
4303 if (op == Cut || op == Delete) {
4304 selection->clear_points ();
4309 struct lt_playlist {
4310 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4311 return a.playlist < b.playlist;
4315 struct PlaylistMapping {
4317 boost::shared_ptr<Playlist> pl;
4319 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4322 /** Remove `clicked_regionview' */
4324 Editor::remove_clicked_region ()
4326 if (clicked_routeview == 0 || clicked_regionview == 0) {
4330 begin_reversible_command (_("remove region"));
4332 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4334 playlist->clear_changes ();
4335 playlist->clear_owned_changes ();
4336 playlist->remove_region (clicked_regionview->region());
4337 if (Config->get_edit_mode() == Ripple)
4338 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4340 /* We might have removed regions, which alters other regions' layering_index,
4341 so we need to do a recursive diff here.
4343 vector<Command*> cmds;
4344 playlist->rdiff (cmds);
4345 _session->add_commands (cmds);
4347 _session->add_command(new StatefulDiffCommand (playlist));
4348 commit_reversible_command ();
4352 /** Remove the selected regions */
4354 Editor::remove_selected_regions ()
4356 RegionSelection rs = get_regions_from_selection_and_entered ();
4358 if (!_session || rs.empty()) {
4362 list<boost::shared_ptr<Region> > regions_to_remove;
4364 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4365 // we can't just remove the region(s) in this loop because
4366 // this removes them from the RegionSelection, and they thus
4367 // disappear from underneath the iterator, and the ++i above
4368 // SEGVs in a puzzling fashion.
4370 // so, first iterate over the regions to be removed from rs and
4371 // add them to the regions_to_remove list, and then
4372 // iterate over the list to actually remove them.
4374 regions_to_remove.push_back ((*i)->region());
4377 vector<boost::shared_ptr<Playlist> > playlists;
4379 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4381 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4384 // is this check necessary?
4388 /* get_regions_from_selection_and_entered() guarantees that
4389 the playlists involved are unique, so there is no need
4393 playlists.push_back (playlist);
4395 playlist->clear_changes ();
4396 playlist->clear_owned_changes ();
4397 playlist->freeze ();
4398 playlist->remove_region (*rl);
4399 if (Config->get_edit_mode() == Ripple)
4400 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4404 vector<boost::shared_ptr<Playlist> >::iterator pl;
4405 bool in_command = false;
4407 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4410 /* We might have removed regions, which alters other regions' layering_index,
4411 so we need to do a recursive diff here.
4415 begin_reversible_command (_("remove region"));
4418 vector<Command*> cmds;
4419 (*pl)->rdiff (cmds);
4420 _session->add_commands (cmds);
4422 _session->add_command(new StatefulDiffCommand (*pl));
4426 commit_reversible_command ();
4430 /** Cut, copy or clear selected regions.
4431 * @param op Operation (Cut, Copy or Clear)
4434 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4436 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4437 a map when we want ordered access to both elements. i think.
4440 vector<PlaylistMapping> pmap;
4442 framepos_t first_position = max_framepos;
4444 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4445 FreezeList freezelist;
4447 /* get ordering correct before we cut/copy */
4449 rs.sort_by_position_and_track ();
4451 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4453 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4455 if (op == Cut || op == Clear || op == Delete) {
4456 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4459 FreezeList::iterator fl;
4461 // only take state if this is a new playlist.
4462 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4468 if (fl == freezelist.end()) {
4469 pl->clear_changes();
4470 pl->clear_owned_changes ();
4472 freezelist.insert (pl);
4477 TimeAxisView* tv = &(*x)->get_time_axis_view();
4478 vector<PlaylistMapping>::iterator z;
4480 for (z = pmap.begin(); z != pmap.end(); ++z) {
4481 if ((*z).tv == tv) {
4486 if (z == pmap.end()) {
4487 pmap.push_back (PlaylistMapping (tv));
4491 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4493 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4496 /* region not yet associated with a playlist (e.g. unfinished
4503 TimeAxisView& tv = (*x)->get_time_axis_view();
4504 boost::shared_ptr<Playlist> npl;
4505 RegionSelection::iterator tmp;
4512 vector<PlaylistMapping>::iterator z;
4514 for (z = pmap.begin(); z != pmap.end(); ++z) {
4515 if ((*z).tv == &tv) {
4520 assert (z != pmap.end());
4523 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4531 boost::shared_ptr<Region> r = (*x)->region();
4532 boost::shared_ptr<Region> _xx;
4538 pl->remove_region (r);
4539 if (Config->get_edit_mode() == Ripple)
4540 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4544 _xx = RegionFactory::create (r);
4545 npl->add_region (_xx, r->position() - first_position);
4546 pl->remove_region (r);
4547 if (Config->get_edit_mode() == Ripple)
4548 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4552 /* copy region before adding, so we're not putting same object into two different playlists */
4553 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4557 pl->remove_region (r);
4558 if (Config->get_edit_mode() == Ripple)
4559 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4568 list<boost::shared_ptr<Playlist> > foo;
4570 /* the pmap is in the same order as the tracks in which selected regions occurred */
4572 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4575 foo.push_back ((*i).pl);
4580 cut_buffer->set (foo);
4584 _last_cut_copy_source_track = 0;
4586 _last_cut_copy_source_track = pmap.front().tv;
4590 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4593 /* We might have removed regions, which alters other regions' layering_index,
4594 so we need to do a recursive diff here.
4596 vector<Command*> cmds;
4597 (*pl)->rdiff (cmds);
4598 _session->add_commands (cmds);
4600 _session->add_command (new StatefulDiffCommand (*pl));
4605 Editor::cut_copy_ranges (CutCopyOp op)
4607 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4609 /* Sort the track selection now, so that it if is used, the playlists
4610 selected by the calls below to cut_copy_clear are in the order that
4611 their tracks appear in the editor. This makes things like paste
4612 of ranges work properly.
4615 sort_track_selection (ts);
4618 if (!entered_track) {
4621 ts.push_back (entered_track);
4624 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4625 (*i)->cut_copy_clear (*selection, op);
4630 Editor::paste (float times, bool from_context)
4632 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4634 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4638 Editor::mouse_paste ()
4643 if (!mouse_frame (where, ignored)) {
4648 paste_internal (where, 1);
4652 Editor::paste_internal (framepos_t position, float times)
4654 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4656 if (cut_buffer->empty(internal_editing())) {
4660 if (position == max_framepos) {
4661 position = get_preferred_edit_position();
4662 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4665 if (position == last_paste_pos) {
4666 /* repeated paste in the same position */
4669 /* paste in new location, reset repeated paste state */
4671 last_paste_pos = position;
4674 /* get everything in the correct order */
4677 if (!selection->tracks.empty()) {
4678 /* If there is a track selection, paste into exactly those tracks and
4679 only those tracks. This allows the user to be explicit and override
4680 the below "do the reasonable thing" logic. */
4681 ts = selection->tracks.filter_to_unique_playlists ();
4682 sort_track_selection (ts);
4684 /* Figure out which track to base the paste at. */
4685 TimeAxisView* base_track = NULL;
4686 if (_edit_point == Editing::EditAtMouse && entered_track) {
4687 /* With the mouse edit point, paste onto the track under the mouse. */
4688 base_track = entered_track;
4689 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4690 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4691 base_track = &entered_regionview->get_time_axis_view();
4692 } else if (_last_cut_copy_source_track) {
4693 /* Paste to the track that the cut/copy came from (see mantis #333). */
4694 base_track = _last_cut_copy_source_track;
4696 /* This is "impossible" since we've copied... well, do nothing. */
4700 /* Walk up to parent if necessary, so base track is a route. */
4701 while (base_track->get_parent()) {
4702 base_track = base_track->get_parent();
4705 /* Add base track and all tracks below it. The paste logic will select
4706 the appropriate object types from the cut buffer in relative order. */
4707 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4708 if ((*i)->order() >= base_track->order()) {
4713 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4714 sort_track_selection (ts);
4716 /* Add automation children of each track in order, for pasting several lines. */
4717 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4718 /* Add any automation children for pasting several lines */
4719 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4724 typedef RouteTimeAxisView::AutomationTracks ATracks;
4725 const ATracks& atracks = rtv->automation_tracks();
4726 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4727 i = ts.insert(i, a->second.get());
4732 /* We now have a list of trackviews starting at base_track, including
4733 automation children, in the order shown in the editor, e.g. R1,
4734 R1.A1, R1.A2, R2, R2.A1, ... */
4737 begin_reversible_command (Operations::paste);
4739 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4740 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4741 /* Only one line copied, and one automation track selected. Do a
4742 "greedy" paste from one automation type to another. */
4744 PasteContext ctx(paste_count, times, ItemCounts(), true);
4745 ts.front()->paste (position, *cut_buffer, ctx);
4749 /* Paste into tracks */
4751 PasteContext ctx(paste_count, times, ItemCounts(), false);
4752 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4753 (*i)->paste (position, *cut_buffer, ctx);
4757 commit_reversible_command ();
4761 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4763 if (regions.empty ()) {
4767 boost::shared_ptr<Playlist> playlist;
4768 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4769 RegionSelection foo;
4771 framepos_t const start_frame = regions.start ();
4772 framepos_t const end_frame = regions.end_frame ();
4773 framecnt_t const gap = end_frame - start_frame + 1;
4775 begin_reversible_command (Operations::duplicate_region);
4777 selection->clear_regions ();
4779 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4781 boost::shared_ptr<Region> r ((*i)->region());
4783 TimeAxisView& tv = (*i)->get_time_axis_view();
4784 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4785 latest_regionviews.clear ();
4786 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4788 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4789 playlist = (*i)->region()->playlist();
4790 playlist->clear_changes ();
4791 playlist->duplicate (r, position, gap, times);
4792 _session->add_command(new StatefulDiffCommand (playlist));
4796 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4800 selection->set (foo);
4803 commit_reversible_command ();
4807 Editor::duplicate_selection (float times)
4809 if (selection->time.empty() || selection->tracks.empty()) {
4813 boost::shared_ptr<Playlist> playlist;
4815 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4817 bool in_command = false;
4819 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4820 if ((playlist = (*i)->playlist()) == 0) {
4823 playlist->clear_changes ();
4825 if (clicked_selection) {
4826 playlist->duplicate_range (selection->time[clicked_selection], times);
4828 playlist->duplicate_ranges (selection->time, times);
4832 begin_reversible_command (_("duplicate range selection"));
4835 _session->add_command (new StatefulDiffCommand (playlist));
4840 // now "move" range selection to after the current range selection
4841 framecnt_t distance = 0;
4843 if (clicked_selection) {
4844 distance = selection->time[clicked_selection].end -
4845 selection->time[clicked_selection].start;
4847 distance = selection->time.end_frame() - selection->time.start();
4850 selection->move_time (distance);
4852 commit_reversible_command ();
4856 /** Reset all selected points to the relevant default value */
4858 Editor::reset_point_selection ()
4860 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4861 ARDOUR::AutomationList::iterator j = (*i)->model ();
4862 (*j)->value = (*i)->line().the_list()->default_value ();
4867 Editor::center_playhead ()
4869 float const page = _visible_canvas_width * samples_per_pixel;
4870 center_screen_internal (playhead_cursor->current_frame (), page);
4874 Editor::center_edit_point ()
4876 float const page = _visible_canvas_width * samples_per_pixel;
4877 center_screen_internal (get_preferred_edit_position(), page);
4880 /** Caller must begin and commit a reversible command */
4882 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4884 playlist->clear_changes ();
4886 _session->add_command (new StatefulDiffCommand (playlist));
4890 Editor::nudge_track (bool use_edit, bool forwards)
4892 boost::shared_ptr<Playlist> playlist;
4893 framepos_t distance;
4894 framepos_t next_distance;
4898 start = get_preferred_edit_position();
4903 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4907 if (selection->tracks.empty()) {
4911 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4912 bool in_command = false;
4914 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4916 if ((playlist = (*i)->playlist()) == 0) {
4920 playlist->clear_changes ();
4921 playlist->clear_owned_changes ();
4923 playlist->nudge_after (start, distance, forwards);
4926 begin_reversible_command (_("nudge track"));
4929 vector<Command*> cmds;
4931 playlist->rdiff (cmds);
4932 _session->add_commands (cmds);
4934 _session->add_command (new StatefulDiffCommand (playlist));
4938 commit_reversible_command ();
4943 Editor::remove_last_capture ()
4945 vector<string> choices;
4952 if (Config->get_verify_remove_last_capture()) {
4953 prompt = _("Do you really want to destroy the last capture?"
4954 "\n(This is destructive and cannot be undone)");
4956 choices.push_back (_("No, do nothing."));
4957 choices.push_back (_("Yes, destroy it."));
4959 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4961 if (prompter.run () == 1) {
4962 _session->remove_last_capture ();
4963 _regions->redisplay ();
4967 _session->remove_last_capture();
4968 _regions->redisplay ();
4973 Editor::normalize_region ()
4979 RegionSelection rs = get_regions_from_selection_and_entered ();
4985 NormalizeDialog dialog (rs.size() > 1);
4987 if (dialog.run () == RESPONSE_CANCEL) {
4991 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4994 /* XXX: should really only count audio regions here */
4995 int const regions = rs.size ();
4997 /* Make a list of the selected audio regions' maximum amplitudes, and also
4998 obtain the maximum amplitude of them all.
5000 list<double> max_amps;
5002 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5003 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5005 dialog.descend (1.0 / regions);
5006 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5009 /* the user cancelled the operation */
5013 max_amps.push_back (a);
5014 max_amp = max (max_amp, a);
5019 list<double>::const_iterator a = max_amps.begin ();
5020 bool in_command = false;
5022 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5023 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5028 arv->region()->clear_changes ();
5030 double const amp = dialog.normalize_individually() ? *a : max_amp;
5032 arv->audio_region()->normalize (amp, dialog.target ());
5035 begin_reversible_command (_("normalize"));
5038 _session->add_command (new StatefulDiffCommand (arv->region()));
5044 commit_reversible_command ();
5050 Editor::reset_region_scale_amplitude ()
5056 RegionSelection rs = get_regions_from_selection_and_entered ();
5062 bool in_command = false;
5064 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5065 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5068 arv->region()->clear_changes ();
5069 arv->audio_region()->set_scale_amplitude (1.0f);
5072 begin_reversible_command ("reset gain");
5075 _session->add_command (new StatefulDiffCommand (arv->region()));
5079 commit_reversible_command ();
5084 Editor::adjust_region_gain (bool up)
5086 RegionSelection rs = get_regions_from_selection_and_entered ();
5088 if (!_session || rs.empty()) {
5092 bool in_command = false;
5094 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5095 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5100 arv->region()->clear_changes ();
5102 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5110 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5113 begin_reversible_command ("adjust region gain");
5116 _session->add_command (new StatefulDiffCommand (arv->region()));
5120 commit_reversible_command ();
5126 Editor::reverse_region ()
5132 Reverse rev (*_session);
5133 apply_filter (rev, _("reverse regions"));
5137 Editor::strip_region_silence ()
5143 RegionSelection rs = get_regions_from_selection_and_entered ();
5149 std::list<RegionView*> audio_only;
5151 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5152 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5154 audio_only.push_back (arv);
5158 assert (!audio_only.empty());
5160 StripSilenceDialog d (_session, audio_only);
5161 int const r = d.run ();
5165 if (r == Gtk::RESPONSE_OK) {
5166 ARDOUR::AudioIntervalMap silences;
5167 d.silences (silences);
5168 StripSilence s (*_session, silences, d.fade_length());
5169 apply_filter (s, _("strip silence"), &d);
5174 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5176 Evoral::Sequence<Evoral::Beats>::Notes selected;
5177 mrv.selection_as_notelist (selected, true);
5179 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5180 v.push_back (selected);
5182 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5183 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5185 return op (mrv.midi_region()->model(), pos_beats, v);
5189 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5195 bool in_command = false;
5197 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5198 RegionSelection::const_iterator tmp = r;
5201 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5204 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5207 begin_reversible_command (op.name ());
5211 _session->add_command (cmd);
5219 commit_reversible_command ();
5224 Editor::fork_region ()
5226 RegionSelection rs = get_regions_from_selection_and_entered ();
5232 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5233 bool in_command = false;
5237 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5238 RegionSelection::iterator tmp = r;
5241 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5245 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5246 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5247 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5250 begin_reversible_command (_("Fork Region(s)"));
5253 playlist->clear_changes ();
5254 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5255 _session->add_command(new StatefulDiffCommand (playlist));
5257 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5265 commit_reversible_command ();
5270 Editor::quantize_region ()
5273 quantize_regions(get_regions_from_selection_and_entered ());
5278 Editor::quantize_regions (const RegionSelection& rs)
5280 if (rs.n_midi_regions() == 0) {
5284 if (!quantize_dialog) {
5285 quantize_dialog = new QuantizeDialog (*this);
5288 quantize_dialog->present ();
5289 const int r = quantize_dialog->run ();
5290 quantize_dialog->hide ();
5292 if (r == Gtk::RESPONSE_OK) {
5293 Quantize quant (quantize_dialog->snap_start(),
5294 quantize_dialog->snap_end(),
5295 quantize_dialog->start_grid_size(),
5296 quantize_dialog->end_grid_size(),
5297 quantize_dialog->strength(),
5298 quantize_dialog->swing(),
5299 quantize_dialog->threshold());
5301 apply_midi_note_edit_op (quant, rs);
5306 Editor::legatize_region (bool shrink_only)
5309 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5314 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5316 if (rs.n_midi_regions() == 0) {
5320 Legatize legatize(shrink_only);
5321 apply_midi_note_edit_op (legatize, rs);
5325 Editor::transform_region ()
5328 transform_regions(get_regions_from_selection_and_entered ());
5333 Editor::transform_regions (const RegionSelection& rs)
5335 if (rs.n_midi_regions() == 0) {
5342 const int r = td.run();
5345 if (r == Gtk::RESPONSE_OK) {
5346 Transform transform(td.get());
5347 apply_midi_note_edit_op(transform, rs);
5352 Editor::transpose_region ()
5355 transpose_regions(get_regions_from_selection_and_entered ());
5360 Editor::transpose_regions (const RegionSelection& rs)
5362 if (rs.n_midi_regions() == 0) {
5367 int const r = d.run ();
5369 if (r == RESPONSE_ACCEPT) {
5370 Transpose transpose(d.semitones ());
5371 apply_midi_note_edit_op (transpose, rs);
5376 Editor::insert_patch_change (bool from_context)
5378 RegionSelection rs = get_regions_from_selection_and_entered ();
5384 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5386 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5387 there may be more than one, but the PatchChangeDialog can only offer
5388 one set of patch menus.
5390 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5392 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5393 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5395 if (d.run() == RESPONSE_CANCEL) {
5399 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5400 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5402 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5403 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5410 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5412 RegionSelection rs = get_regions_from_selection_and_entered ();
5418 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5419 bool in_command = false;
5424 int const N = rs.size ();
5426 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5427 RegionSelection::iterator tmp = r;
5430 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5432 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5435 progress->descend (1.0 / N);
5438 if (arv->audio_region()->apply (filter, progress) == 0) {
5440 playlist->clear_changes ();
5441 playlist->clear_owned_changes ();
5443 if (filter.results.empty ()) {
5445 /* no regions returned; remove the old one */
5446 playlist->remove_region (arv->region ());
5450 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5452 /* first region replaces the old one */
5453 playlist->replace_region (arv->region(), *res, (*res)->position());
5457 while (res != filter.results.end()) {
5458 playlist->add_region (*res, (*res)->position());
5463 /* We might have removed regions, which alters other regions' layering_index,
5464 so we need to do a recursive diff here.
5468 begin_reversible_command (command);
5471 vector<Command*> cmds;
5472 playlist->rdiff (cmds);
5473 _session->add_commands (cmds);
5475 _session->add_command(new StatefulDiffCommand (playlist));
5479 progress->ascend ();
5488 commit_reversible_command ();
5493 Editor::external_edit_region ()
5499 Editor::reset_region_gain_envelopes ()
5501 RegionSelection rs = get_regions_from_selection_and_entered ();
5503 if (!_session || rs.empty()) {
5507 bool in_command = false;
5509 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5510 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5512 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5513 XMLNode& before (alist->get_state());
5515 arv->audio_region()->set_default_envelope ();
5518 begin_reversible_command (_("reset region gain"));
5521 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5526 commit_reversible_command ();
5531 Editor::set_region_gain_visibility (RegionView* rv)
5533 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5535 arv->update_envelope_visibility();
5540 Editor::set_gain_envelope_visibility ()
5546 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5547 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5549 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5555 Editor::toggle_gain_envelope_active ()
5557 if (_ignore_region_action) {
5561 RegionSelection rs = get_regions_from_selection_and_entered ();
5563 if (!_session || rs.empty()) {
5567 bool in_command = false;
5569 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5570 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5572 arv->region()->clear_changes ();
5573 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5576 begin_reversible_command (_("region gain envelope active"));
5579 _session->add_command (new StatefulDiffCommand (arv->region()));
5584 commit_reversible_command ();
5589 Editor::toggle_region_lock ()
5591 if (_ignore_region_action) {
5595 RegionSelection rs = get_regions_from_selection_and_entered ();
5597 if (!_session || rs.empty()) {
5601 begin_reversible_command (_("toggle region lock"));
5603 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5604 (*i)->region()->clear_changes ();
5605 (*i)->region()->set_locked (!(*i)->region()->locked());
5606 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5609 commit_reversible_command ();
5613 Editor::toggle_region_video_lock ()
5615 if (_ignore_region_action) {
5619 RegionSelection rs = get_regions_from_selection_and_entered ();
5621 if (!_session || rs.empty()) {
5625 begin_reversible_command (_("Toggle Video Lock"));
5627 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5628 (*i)->region()->clear_changes ();
5629 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5630 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5633 commit_reversible_command ();
5637 Editor::toggle_region_lock_style ()
5639 if (_ignore_region_action) {
5643 RegionSelection rs = get_regions_from_selection_and_entered ();
5645 if (!_session || rs.empty()) {
5649 begin_reversible_command (_("region lock style"));
5651 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5652 (*i)->region()->clear_changes ();
5653 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5654 (*i)->region()->set_position_lock_style (ns);
5655 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5658 commit_reversible_command ();
5662 Editor::toggle_opaque_region ()
5664 if (_ignore_region_action) {
5668 RegionSelection rs = get_regions_from_selection_and_entered ();
5670 if (!_session || rs.empty()) {
5674 begin_reversible_command (_("change region opacity"));
5676 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5677 (*i)->region()->clear_changes ();
5678 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5679 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5682 commit_reversible_command ();
5686 Editor::toggle_record_enable ()
5688 bool new_state = false;
5690 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5691 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5694 if (!rtav->is_track())
5698 new_state = !rtav->track()->record_enabled();
5702 rtav->track()->set_record_enabled (new_state, Controllable::UseGroup);
5707 Editor::toggle_solo ()
5709 bool new_state = false;
5711 boost::shared_ptr<RouteList> rl (new RouteList);
5713 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5714 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5721 new_state = !rtav->route()->soloed ();
5725 rl->push_back (rtav->route());
5728 _session->set_solo (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
5732 Editor::toggle_mute ()
5734 bool new_state = false;
5736 boost::shared_ptr<RouteList> rl (new RouteList);
5738 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5739 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5746 new_state = !rtav->route()->muted();
5750 rl->push_back (rtav->route());
5753 _session->set_mute (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
5757 Editor::toggle_solo_isolate ()
5763 Editor::fade_range ()
5765 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5767 begin_reversible_command (_("fade range"));
5769 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5770 (*i)->fade_range (selection->time);
5773 commit_reversible_command ();
5778 Editor::set_fade_length (bool in)
5780 RegionSelection rs = get_regions_from_selection_and_entered ();
5786 /* we need a region to measure the offset from the start */
5788 RegionView* rv = rs.front ();
5790 framepos_t pos = get_preferred_edit_position();
5794 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5795 /* edit point is outside the relevant region */
5800 if (pos <= rv->region()->position()) {
5804 len = pos - rv->region()->position();
5805 cmd = _("set fade in length");
5807 if (pos >= rv->region()->last_frame()) {
5811 len = rv->region()->last_frame() - pos;
5812 cmd = _("set fade out length");
5815 bool in_command = false;
5817 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5818 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5824 boost::shared_ptr<AutomationList> alist;
5826 alist = tmp->audio_region()->fade_in();
5828 alist = tmp->audio_region()->fade_out();
5831 XMLNode &before = alist->get_state();
5834 tmp->audio_region()->set_fade_in_length (len);
5835 tmp->audio_region()->set_fade_in_active (true);
5837 tmp->audio_region()->set_fade_out_length (len);
5838 tmp->audio_region()->set_fade_out_active (true);
5842 begin_reversible_command (cmd);
5845 XMLNode &after = alist->get_state();
5846 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5850 commit_reversible_command ();
5855 Editor::set_fade_in_shape (FadeShape shape)
5857 RegionSelection rs = get_regions_from_selection_and_entered ();
5862 bool in_command = false;
5864 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5865 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5871 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5872 XMLNode &before = alist->get_state();
5874 tmp->audio_region()->set_fade_in_shape (shape);
5877 begin_reversible_command (_("set fade in shape"));
5880 XMLNode &after = alist->get_state();
5881 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5885 commit_reversible_command ();
5890 Editor::set_fade_out_shape (FadeShape shape)
5892 RegionSelection rs = get_regions_from_selection_and_entered ();
5897 bool in_command = false;
5899 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5900 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5906 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5907 XMLNode &before = alist->get_state();
5909 tmp->audio_region()->set_fade_out_shape (shape);
5912 begin_reversible_command (_("set fade out shape"));
5915 XMLNode &after = alist->get_state();
5916 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5920 commit_reversible_command ();
5925 Editor::set_fade_in_active (bool yn)
5927 RegionSelection rs = get_regions_from_selection_and_entered ();
5932 bool in_command = false;
5934 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5935 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5942 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5944 ar->clear_changes ();
5945 ar->set_fade_in_active (yn);
5948 begin_reversible_command (_("set fade in active"));
5951 _session->add_command (new StatefulDiffCommand (ar));
5955 commit_reversible_command ();
5960 Editor::set_fade_out_active (bool yn)
5962 RegionSelection rs = get_regions_from_selection_and_entered ();
5967 bool in_command = false;
5969 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5970 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5976 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5978 ar->clear_changes ();
5979 ar->set_fade_out_active (yn);
5982 begin_reversible_command (_("set fade out active"));
5985 _session->add_command(new StatefulDiffCommand (ar));
5989 commit_reversible_command ();
5994 Editor::toggle_region_fades (int dir)
5996 if (_ignore_region_action) {
6000 boost::shared_ptr<AudioRegion> ar;
6003 RegionSelection rs = get_regions_from_selection_and_entered ();
6009 RegionSelection::iterator i;
6010 for (i = rs.begin(); i != rs.end(); ++i) {
6011 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6013 yn = ar->fade_out_active ();
6015 yn = ar->fade_in_active ();
6021 if (i == rs.end()) {
6025 /* XXX should this undo-able? */
6026 bool in_command = false;
6028 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6029 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6032 ar->clear_changes ();
6034 if (dir == 1 || dir == 0) {
6035 ar->set_fade_in_active (!yn);
6038 if (dir == -1 || dir == 0) {
6039 ar->set_fade_out_active (!yn);
6042 begin_reversible_command (_("toggle fade active"));
6045 _session->add_command(new StatefulDiffCommand (ar));
6049 commit_reversible_command ();
6054 /** Update region fade visibility after its configuration has been changed */
6056 Editor::update_region_fade_visibility ()
6058 bool _fade_visibility = _session->config.get_show_region_fades ();
6060 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6061 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6063 if (_fade_visibility) {
6064 v->audio_view()->show_all_fades ();
6066 v->audio_view()->hide_all_fades ();
6073 Editor::set_edit_point ()
6078 if (!mouse_frame (where, ignored)) {
6084 if (selection->markers.empty()) {
6086 mouse_add_new_marker (where);
6091 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6094 loc->move_to (where);
6100 Editor::set_playhead_cursor ()
6102 if (entered_marker) {
6103 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6108 if (!mouse_frame (where, ignored)) {
6115 _session->request_locate (where, _session->transport_rolling());
6119 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6120 cancel_time_selection();
6125 Editor::split_region ()
6127 if (_drags->active ()) {
6131 //if a range is selected, separate it
6132 if ( !selection->time.empty()) {
6133 separate_regions_between (selection->time);
6137 //if no range was selected, try to find some regions to split
6138 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6140 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6142 framepos_t where = get_preferred_edit_position ();
6148 split_regions_at (where, rs);
6152 struct EditorOrderRouteSorter {
6153 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6154 return a->order_key () < b->order_key ();
6159 Editor::select_next_route()
6161 if (selection->tracks.empty()) {
6162 selection->set (track_views.front());
6166 TimeAxisView* current = selection->tracks.front();
6170 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6171 if (*i == current) {
6173 if (i != track_views.end()) {
6176 current = (*(track_views.begin()));
6177 //selection->set (*(track_views.begin()));
6182 rui = dynamic_cast<RouteUI *>(current);
6183 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6185 selection->set(current);
6187 ensure_time_axis_view_is_visible (*current, false);
6191 Editor::select_prev_route()
6193 if (selection->tracks.empty()) {
6194 selection->set (track_views.front());
6198 TimeAxisView* current = selection->tracks.front();
6202 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6203 if (*i == current) {
6205 if (i != track_views.rend()) {
6208 current = *(track_views.rbegin());
6213 rui = dynamic_cast<RouteUI *>(current);
6214 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6216 selection->set (current);
6218 ensure_time_axis_view_is_visible (*current, false);
6222 Editor::set_loop_from_selection (bool play)
6224 if (_session == 0) {
6228 framepos_t start, end;
6229 if (!get_selection_extents ( start, end))
6232 set_loop_range (start, end, _("set loop range from selection"));
6235 _session->request_play_loop (true, true);
6240 Editor::set_loop_from_region (bool play)
6242 framepos_t start, end;
6243 if (!get_selection_extents ( start, end))
6246 set_loop_range (start, end, _("set loop range from region"));
6249 _session->request_locate (start, true);
6250 _session->request_play_loop (true);
6255 Editor::set_punch_from_selection ()
6257 if (_session == 0) {
6261 framepos_t start, end;
6262 if (!get_selection_extents ( start, end))
6265 set_punch_range (start, end, _("set punch range from selection"));
6269 Editor::set_session_extents_from_selection ()
6271 if (_session == 0) {
6275 framepos_t start, end;
6276 if (!get_selection_extents ( start, end))
6280 if ((loc = _session->locations()->session_range_location()) == 0) {
6281 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6283 XMLNode &before = loc->get_state();
6285 _session->set_session_extents ( start, end );
6287 XMLNode &after = loc->get_state();
6289 begin_reversible_command (_("set session start/end from selection"));
6291 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6293 commit_reversible_command ();
6298 Editor::set_punch_start_from_edit_point ()
6302 framepos_t start = 0;
6303 framepos_t end = max_framepos;
6305 //use the existing punch end, if any
6306 Location* tpl = transport_punch_location();
6311 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6312 start = _session->audible_frame();
6314 start = get_preferred_edit_position();
6317 //snap the selection start/end
6320 //if there's not already a sensible selection endpoint, go "forever"
6321 if ( start > end ) {
6325 set_punch_range (start, end, _("set punch start from EP"));
6331 Editor::set_punch_end_from_edit_point ()
6335 framepos_t start = 0;
6336 framepos_t end = max_framepos;
6338 //use the existing punch start, if any
6339 Location* tpl = transport_punch_location();
6341 start = tpl->start();
6344 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6345 end = _session->audible_frame();
6347 end = get_preferred_edit_position();
6350 //snap the selection start/end
6353 set_punch_range (start, end, _("set punch end from EP"));
6359 Editor::set_loop_start_from_edit_point ()
6363 framepos_t start = 0;
6364 framepos_t end = max_framepos;
6366 //use the existing loop end, if any
6367 Location* tpl = transport_loop_location();
6372 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6373 start = _session->audible_frame();
6375 start = get_preferred_edit_position();
6378 //snap the selection start/end
6381 //if there's not already a sensible selection endpoint, go "forever"
6382 if ( start > end ) {
6386 set_loop_range (start, end, _("set loop start from EP"));
6392 Editor::set_loop_end_from_edit_point ()
6396 framepos_t start = 0;
6397 framepos_t end = max_framepos;
6399 //use the existing loop start, if any
6400 Location* tpl = transport_loop_location();
6402 start = tpl->start();
6405 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6406 end = _session->audible_frame();
6408 end = get_preferred_edit_position();
6411 //snap the selection start/end
6414 set_loop_range (start, end, _("set loop end from EP"));
6419 Editor::set_punch_from_region ()
6421 framepos_t start, end;
6422 if (!get_selection_extents ( start, end))
6425 set_punch_range (start, end, _("set punch range from region"));
6429 Editor::pitch_shift_region ()
6431 RegionSelection rs = get_regions_from_selection_and_entered ();
6433 RegionSelection audio_rs;
6434 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6435 if (dynamic_cast<AudioRegionView*> (*i)) {
6436 audio_rs.push_back (*i);
6440 if (audio_rs.empty()) {
6444 pitch_shift (audio_rs, 1.2);
6448 Editor::set_tempo_from_region ()
6450 RegionSelection rs = get_regions_from_selection_and_entered ();
6452 if (!_session || rs.empty()) {
6456 RegionView* rv = rs.front();
6458 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6462 Editor::use_range_as_bar ()
6464 framepos_t start, end;
6465 if (get_edit_op_range (start, end)) {
6466 define_one_bar (start, end);
6471 Editor::define_one_bar (framepos_t start, framepos_t end)
6473 framepos_t length = end - start;
6475 const Meter& m (_session->tempo_map().meter_at (start));
6477 /* length = 1 bar */
6479 /* now we want frames per beat.
6480 we have frames per bar, and beats per bar, so ...
6483 /* XXXX METER MATH */
6485 double frames_per_beat = length / m.divisions_per_bar();
6487 /* beats per minute = */
6489 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6491 /* now decide whether to:
6493 (a) set global tempo
6494 (b) add a new tempo marker
6498 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6500 bool do_global = false;
6502 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6504 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6505 at the start, or create a new marker
6508 vector<string> options;
6509 options.push_back (_("Cancel"));
6510 options.push_back (_("Add new marker"));
6511 options.push_back (_("Set global tempo"));
6514 _("Define one bar"),
6515 _("Do you want to set the global tempo or add a new tempo marker?"),
6519 c.set_default_response (2);
6535 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6536 if the marker is at the region starter, change it, otherwise add
6541 begin_reversible_command (_("set tempo from region"));
6542 XMLNode& before (_session->tempo_map().get_state());
6545 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6546 } else if (t.frame() == start) {
6547 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6549 Timecode::BBT_Time bbt;
6550 _session->tempo_map().bbt_time (start, bbt);
6551 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6554 XMLNode& after (_session->tempo_map().get_state());
6556 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6557 commit_reversible_command ();
6561 Editor::split_region_at_transients ()
6563 AnalysisFeatureList positions;
6565 RegionSelection rs = get_regions_from_selection_and_entered ();
6567 if (!_session || rs.empty()) {
6571 begin_reversible_command (_("split regions"));
6573 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6575 RegionSelection::iterator tmp;
6580 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6582 if (ar && (ar->get_transients (positions) == 0)) {
6583 split_region_at_points ((*i)->region(), positions, true);
6590 commit_reversible_command ();
6595 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6597 bool use_rhythmic_rodent = false;
6599 boost::shared_ptr<Playlist> pl = r->playlist();
6601 list<boost::shared_ptr<Region> > new_regions;
6607 if (positions.empty()) {
6612 if (positions.size() > 20 && can_ferret) {
6613 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);
6614 MessageDialog msg (msgstr,
6617 Gtk::BUTTONS_OK_CANCEL);
6620 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6621 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6623 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6626 msg.set_title (_("Excessive split?"));
6629 int response = msg.run();
6635 case RESPONSE_APPLY:
6636 use_rhythmic_rodent = true;
6643 if (use_rhythmic_rodent) {
6644 show_rhythm_ferret ();
6648 AnalysisFeatureList::const_iterator x;
6650 pl->clear_changes ();
6651 pl->clear_owned_changes ();
6653 x = positions.begin();
6655 if (x == positions.end()) {
6660 pl->remove_region (r);
6664 while (x != positions.end()) {
6666 /* deal with positons that are out of scope of present region bounds */
6667 if (*x <= 0 || *x > r->length()) {
6672 /* file start = original start + how far we from the initial position ?
6675 framepos_t file_start = r->start() + pos;
6677 /* length = next position - current position
6680 framepos_t len = (*x) - pos;
6682 /* XXX we do we really want to allow even single-sample regions?
6683 shouldn't we have some kind of lower limit on region size?
6692 if (RegionFactory::region_name (new_name, r->name())) {
6696 /* do NOT announce new regions 1 by one, just wait till they are all done */
6700 plist.add (ARDOUR::Properties::start, file_start);
6701 plist.add (ARDOUR::Properties::length, len);
6702 plist.add (ARDOUR::Properties::name, new_name);
6703 plist.add (ARDOUR::Properties::layer, 0);
6705 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6706 /* because we set annouce to false, manually add the new region to the
6709 RegionFactory::map_add (nr);
6711 pl->add_region (nr, r->position() + pos);
6714 new_regions.push_front(nr);
6723 RegionFactory::region_name (new_name, r->name());
6725 /* Add the final region */
6728 plist.add (ARDOUR::Properties::start, r->start() + pos);
6729 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6730 plist.add (ARDOUR::Properties::name, new_name);
6731 plist.add (ARDOUR::Properties::layer, 0);
6733 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6734 /* because we set annouce to false, manually add the new region to the
6737 RegionFactory::map_add (nr);
6738 pl->add_region (nr, r->position() + pos);
6741 new_regions.push_front(nr);
6746 /* We might have removed regions, which alters other regions' layering_index,
6747 so we need to do a recursive diff here.
6749 vector<Command*> cmds;
6751 _session->add_commands (cmds);
6753 _session->add_command (new StatefulDiffCommand (pl));
6757 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6758 set_selected_regionview_from_region_list ((*i), Selection::Add);
6764 Editor::place_transient()
6770 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6776 framepos_t where = get_preferred_edit_position();
6778 begin_reversible_command (_("place transient"));
6780 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6781 framepos_t position = (*r)->region()->position();
6782 (*r)->region()->add_transient(where - position);
6785 commit_reversible_command ();
6789 Editor::remove_transient(ArdourCanvas::Item* item)
6795 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6798 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6799 _arv->remove_transient (*(float*) _line->get_data ("position"));
6803 Editor::snap_regions_to_grid ()
6805 list <boost::shared_ptr<Playlist > > used_playlists;
6807 RegionSelection rs = get_regions_from_selection_and_entered ();
6809 if (!_session || rs.empty()) {
6813 begin_reversible_command (_("snap regions to grid"));
6815 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6817 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6819 if (!pl->frozen()) {
6820 /* we haven't seen this playlist before */
6822 /* remember used playlists so we can thaw them later */
6823 used_playlists.push_back(pl);
6827 framepos_t start_frame = (*r)->region()->first_frame ();
6828 snap_to (start_frame);
6829 (*r)->region()->set_position (start_frame);
6832 while (used_playlists.size() > 0) {
6833 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6835 used_playlists.pop_front();
6838 commit_reversible_command ();
6842 Editor::close_region_gaps ()
6844 list <boost::shared_ptr<Playlist > > used_playlists;
6846 RegionSelection rs = get_regions_from_selection_and_entered ();
6848 if (!_session || rs.empty()) {
6852 Dialog dialog (_("Close Region Gaps"));
6855 table.set_spacings (12);
6856 table.set_border_width (12);
6857 Label* l = manage (left_aligned_label (_("Crossfade length")));
6858 table.attach (*l, 0, 1, 0, 1);
6860 SpinButton spin_crossfade (1, 0);
6861 spin_crossfade.set_range (0, 15);
6862 spin_crossfade.set_increments (1, 1);
6863 spin_crossfade.set_value (5);
6864 table.attach (spin_crossfade, 1, 2, 0, 1);
6866 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6868 l = manage (left_aligned_label (_("Pull-back length")));
6869 table.attach (*l, 0, 1, 1, 2);
6871 SpinButton spin_pullback (1, 0);
6872 spin_pullback.set_range (0, 100);
6873 spin_pullback.set_increments (1, 1);
6874 spin_pullback.set_value(30);
6875 table.attach (spin_pullback, 1, 2, 1, 2);
6877 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6879 dialog.get_vbox()->pack_start (table);
6880 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6881 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6884 if (dialog.run () == RESPONSE_CANCEL) {
6888 framepos_t crossfade_len = spin_crossfade.get_value();
6889 framepos_t pull_back_frames = spin_pullback.get_value();
6891 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6892 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6894 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6896 begin_reversible_command (_("close region gaps"));
6899 boost::shared_ptr<Region> last_region;
6901 rs.sort_by_position_and_track();
6903 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6905 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6907 if (!pl->frozen()) {
6908 /* we haven't seen this playlist before */
6910 /* remember used playlists so we can thaw them later */
6911 used_playlists.push_back(pl);
6915 framepos_t position = (*r)->region()->position();
6917 if (idx == 0 || position < last_region->position()){
6918 last_region = (*r)->region();
6923 (*r)->region()->trim_front( (position - pull_back_frames));
6924 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6926 last_region = (*r)->region();
6931 while (used_playlists.size() > 0) {
6932 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6934 used_playlists.pop_front();
6937 commit_reversible_command ();
6941 Editor::tab_to_transient (bool forward)
6943 AnalysisFeatureList positions;
6945 RegionSelection rs = get_regions_from_selection_and_entered ();
6951 framepos_t pos = _session->audible_frame ();
6953 if (!selection->tracks.empty()) {
6955 /* don't waste time searching for transients in duplicate playlists.
6958 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6960 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6962 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6965 boost::shared_ptr<Track> tr = rtv->track();
6967 boost::shared_ptr<Playlist> pl = tr->playlist ();
6969 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6972 positions.push_back (result);
6985 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6986 (*r)->region()->get_transients (positions);
6990 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6993 AnalysisFeatureList::iterator x;
6995 for (x = positions.begin(); x != positions.end(); ++x) {
7001 if (x != positions.end ()) {
7002 _session->request_locate (*x);
7006 AnalysisFeatureList::reverse_iterator x;
7008 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7014 if (x != positions.rend ()) {
7015 _session->request_locate (*x);
7021 Editor::playhead_forward_to_grid ()
7027 framepos_t pos = playhead_cursor->current_frame ();
7028 if (pos < max_framepos - 1) {
7030 snap_to_internal (pos, RoundUpAlways, false);
7031 _session->request_locate (pos);
7037 Editor::playhead_backward_to_grid ()
7043 framepos_t pos = playhead_cursor->current_frame ();
7046 snap_to_internal (pos, RoundDownAlways, false);
7047 _session->request_locate (pos);
7052 Editor::set_track_height (Height h)
7054 TrackSelection& ts (selection->tracks);
7056 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7057 (*x)->set_height_enum (h);
7062 Editor::toggle_tracks_active ()
7064 TrackSelection& ts (selection->tracks);
7066 bool target = false;
7072 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7073 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7077 target = !rtv->_route->active();
7080 rtv->_route->set_active (target, this);
7086 Editor::remove_tracks ()
7088 /* this will delete GUI objects that may be the subject of an event
7089 handler in which this method is called. Defer actual deletion to the
7090 next idle callback, when all event handling is finished.
7092 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7096 Editor::idle_remove_tracks ()
7099 return false; /* do not call again */
7103 Editor::_remove_tracks ()
7105 TrackSelection& ts (selection->tracks);
7111 vector<string> choices;
7115 const char* trackstr;
7117 vector<boost::shared_ptr<Route> > routes;
7118 bool special_bus = false;
7120 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7121 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7125 if (rtv->is_track()) {
7130 routes.push_back (rtv->_route);
7132 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7137 if (special_bus && !Config->get_allow_special_bus_removal()) {
7138 MessageDialog msg (_("That would be bad news ...."),
7142 msg.set_secondary_text (string_compose (_(
7143 "Removing the master or monitor bus is such a bad idea\n\
7144 that %1 is not going to allow it.\n\
7146 If you really want to do this sort of thing\n\
7147 edit your ardour.rc file to set the\n\
7148 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7155 if (ntracks + nbusses == 0) {
7159 trackstr = P_("track", "tracks", ntracks);
7160 busstr = P_("bus", "busses", nbusses);
7164 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7165 "(You may also lose the playlists associated with the %2)\n\n"
7166 "This action cannot be undone, and the session file will be overwritten!"),
7167 ntracks, trackstr, nbusses, busstr);
7169 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7170 "(You may also lose the playlists associated with the %2)\n\n"
7171 "This action cannot be undone, and the session file will be overwritten!"),
7174 } else if (nbusses) {
7175 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7176 "This action cannot be undone, and the session file will be overwritten"),
7180 choices.push_back (_("No, do nothing."));
7181 if (ntracks + nbusses > 1) {
7182 choices.push_back (_("Yes, remove them."));
7184 choices.push_back (_("Yes, remove it."));
7189 title = string_compose (_("Remove %1"), trackstr);
7191 title = string_compose (_("Remove %1"), busstr);
7194 Choice prompter (title, prompt, choices);
7196 if (prompter.run () != 1) {
7201 Session::StateProtector sp (_session);
7202 DisplaySuspender ds;
7203 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7204 _session->remove_route (*x);
7210 Editor::do_insert_time ()
7212 if (selection->tracks.empty()) {
7216 InsertRemoveTimeDialog d (*this);
7217 int response = d.run ();
7219 if (response != RESPONSE_OK) {
7223 if (d.distance() == 0) {
7228 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7230 d.intersected_region_action (),
7234 d.move_glued_markers(),
7235 d.move_locked_markers(),
7241 Editor::insert_time (
7242 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7243 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7247 if (Config->get_edit_mode() == Lock) {
7250 bool in_command = false;
7252 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7254 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7258 /* don't operate on any playlist more than once, which could
7259 * happen if "all playlists" is enabled, but there is more
7260 * than 1 track using playlists "from" a given track.
7263 set<boost::shared_ptr<Playlist> > pl;
7265 if (all_playlists) {
7266 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7267 if (rtav && rtav->track ()) {
7268 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7269 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7274 if ((*x)->playlist ()) {
7275 pl.insert ((*x)->playlist ());
7279 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7281 (*i)->clear_changes ();
7282 (*i)->clear_owned_changes ();
7284 if (opt == SplitIntersected) {
7288 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7291 begin_reversible_command (_("insert time"));
7294 vector<Command*> cmds;
7296 _session->add_commands (cmds);
7298 _session->add_command (new StatefulDiffCommand (*i));
7302 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7305 begin_reversible_command (_("insert time"));
7308 rtav->route ()->shift (pos, frames);
7315 XMLNode& before (_session->locations()->get_state());
7316 Locations::LocationList copy (_session->locations()->list());
7318 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7320 Locations::LocationList::const_iterator tmp;
7322 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7323 bool const was_locked = (*i)->locked ();
7324 if (locked_markers_too) {
7328 if ((*i)->start() >= pos) {
7329 // move end first, in case we're moving by more than the length of the range
7330 if (!(*i)->is_mark()) {
7331 (*i)->set_end ((*i)->end() + frames);
7333 (*i)->set_start ((*i)->start() + frames);
7345 begin_reversible_command (_("insert time"));
7348 XMLNode& after (_session->locations()->get_state());
7349 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7355 begin_reversible_command (_("insert time"));
7358 XMLNode& before (_session->tempo_map().get_state());
7359 _session->tempo_map().insert_time (pos, frames);
7360 XMLNode& after (_session->tempo_map().get_state());
7361 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7365 commit_reversible_command ();
7370 Editor::do_remove_time ()
7372 if (selection->tracks.empty()) {
7376 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7377 InsertRemoveTimeDialog d (*this, true);
7379 int response = d.run ();
7381 if (response != RESPONSE_OK) {
7385 framecnt_t distance = d.distance();
7387 if (distance == 0) {
7397 d.move_glued_markers(),
7398 d.move_locked_markers(),
7404 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7405 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7407 if (Config->get_edit_mode() == Lock) {
7408 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7411 bool in_command = false;
7413 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7415 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7419 XMLNode &before = pl->get_state();
7421 std::list<AudioRange> rl;
7422 AudioRange ar(pos, pos+frames, 0);
7425 pl->shift (pos, -frames, true, ignore_music_glue);
7428 begin_reversible_command (_("remove time"));
7431 XMLNode &after = pl->get_state();
7433 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7437 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7440 begin_reversible_command (_("remove time"));
7443 rtav->route ()->shift (pos, -frames);
7447 std::list<Location*> loc_kill_list;
7452 XMLNode& before (_session->locations()->get_state());
7453 Locations::LocationList copy (_session->locations()->list());
7455 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7456 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7458 bool const was_locked = (*i)->locked ();
7459 if (locked_markers_too) {
7463 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7464 if ((*i)->end() >= pos
7465 && (*i)->end() < pos+frames
7466 && (*i)->start() >= pos
7467 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7469 loc_kill_list.push_back(*i);
7470 } else { // only start or end is included, try to do the right thing
7471 // move start before moving end, to avoid trying to move the end to before the start
7472 // if we're removing more time than the length of the range
7473 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7474 // start is within cut
7475 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7477 } else if ((*i)->start() >= pos+frames) {
7478 // start (and thus entire range) lies beyond end of cut
7479 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7482 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7483 // end is inside cut
7484 (*i)->set_end (pos); // bring the end to the cut
7486 } else if ((*i)->end() >= pos+frames) {
7487 // end is beyond end of cut
7488 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7493 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7494 loc_kill_list.push_back(*i);
7496 } else if ((*i)->start() >= pos) {
7497 (*i)->set_start ((*i)->start() -frames);
7507 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7508 _session->locations()->remove( *i );
7513 begin_reversible_command (_("remove time"));
7516 XMLNode& after (_session->locations()->get_state());
7517 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7522 XMLNode& before (_session->tempo_map().get_state());
7524 if (_session->tempo_map().remove_time (pos, frames) ) {
7526 begin_reversible_command (_("remove time"));
7529 XMLNode& after (_session->tempo_map().get_state());
7530 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7535 commit_reversible_command ();
7540 Editor::fit_selection ()
7542 if (!selection->tracks.empty()) {
7543 fit_tracks (selection->tracks);
7547 /* no selected tracks - use tracks with selected regions */
7549 if (!selection->regions.empty()) {
7550 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7551 tvl.push_back (&(*r)->get_time_axis_view ());
7557 } else if (internal_editing()) {
7558 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7561 if (entered_track) {
7562 tvl.push_back (entered_track);
7571 Editor::fit_tracks (TrackViewList & tracks)
7573 if (tracks.empty()) {
7577 uint32_t child_heights = 0;
7578 int visible_tracks = 0;
7580 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7582 if (!(*t)->marked_for_display()) {
7586 child_heights += (*t)->effective_height() - (*t)->current_height();
7590 /* compute the per-track height from:
7592 total canvas visible height -
7593 height that will be taken by visible children of selected
7594 tracks - height of the ruler/hscroll area
7596 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7597 double first_y_pos = DBL_MAX;
7599 if (h < TimeAxisView::preset_height (HeightSmall)) {
7600 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7601 /* too small to be displayed */
7605 undo_visual_stack.push_back (current_visual_state (true));
7606 PBD::Unwinder<bool> nsv (no_save_visual, true);
7608 /* build a list of all tracks, including children */
7611 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7613 TimeAxisView::Children c = (*i)->get_child_list ();
7614 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7615 all.push_back (j->get());
7620 // find selection range.
7621 // if someone knows how to user TrackViewList::iterator for this
7623 int selected_top = -1;
7624 int selected_bottom = -1;
7626 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7627 if ((*t)->marked_for_display ()) {
7628 if (tracks.contains(*t)) {
7629 if (selected_top == -1) {
7632 selected_bottom = i;
7638 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7639 if ((*t)->marked_for_display ()) {
7640 if (tracks.contains(*t)) {
7641 (*t)->set_height (h);
7642 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7644 if (i > selected_top && i < selected_bottom) {
7645 hide_track_in_display (*t);
7652 set the controls_layout height now, because waiting for its size
7653 request signal handler will cause the vertical adjustment setting to fail
7656 controls_layout.property_height () = _full_canvas_height;
7657 vertical_adjustment.set_value (first_y_pos);
7659 redo_visual_stack.push_back (current_visual_state (true));
7661 visible_tracks_selector.set_text (_("Sel"));
7665 Editor::save_visual_state (uint32_t n)
7667 while (visual_states.size() <= n) {
7668 visual_states.push_back (0);
7671 if (visual_states[n] != 0) {
7672 delete visual_states[n];
7675 visual_states[n] = current_visual_state (true);
7680 Editor::goto_visual_state (uint32_t n)
7682 if (visual_states.size() <= n) {
7686 if (visual_states[n] == 0) {
7690 use_visual_state (*visual_states[n]);
7694 Editor::start_visual_state_op (uint32_t n)
7696 save_visual_state (n);
7698 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7700 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7701 pup->set_text (buf);
7706 Editor::cancel_visual_state_op (uint32_t n)
7708 goto_visual_state (n);
7712 Editor::toggle_region_mute ()
7714 if (_ignore_region_action) {
7718 RegionSelection rs = get_regions_from_selection_and_entered ();
7724 if (rs.size() > 1) {
7725 begin_reversible_command (_("mute regions"));
7727 begin_reversible_command (_("mute region"));
7730 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7732 (*i)->region()->playlist()->clear_changes ();
7733 (*i)->region()->set_muted (!(*i)->region()->muted ());
7734 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7738 commit_reversible_command ();
7742 Editor::combine_regions ()
7744 /* foreach track with selected regions, take all selected regions
7745 and join them into a new region containing the subregions (as a
7749 typedef set<RouteTimeAxisView*> RTVS;
7752 if (selection->regions.empty()) {
7756 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7757 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7760 tracks.insert (rtv);
7764 begin_reversible_command (_("combine regions"));
7766 vector<RegionView*> new_selection;
7768 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7771 if ((rv = (*i)->combine_regions ()) != 0) {
7772 new_selection.push_back (rv);
7776 selection->clear_regions ();
7777 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7778 selection->add (*i);
7781 commit_reversible_command ();
7785 Editor::uncombine_regions ()
7787 typedef set<RouteTimeAxisView*> RTVS;
7790 if (selection->regions.empty()) {
7794 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7795 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7798 tracks.insert (rtv);
7802 begin_reversible_command (_("uncombine regions"));
7804 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7805 (*i)->uncombine_regions ();
7808 commit_reversible_command ();
7812 Editor::toggle_midi_input_active (bool flip_others)
7815 boost::shared_ptr<RouteList> rl (new RouteList);
7817 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7818 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7824 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7827 rl->push_back (rtav->route());
7828 onoff = !mt->input_active();
7832 _session->set_exclusive_input_active (rl, onoff, flip_others);
7839 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7841 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7842 lock_dialog->get_vbox()->pack_start (*padlock);
7844 ArdourButton* b = manage (new ArdourButton);
7845 b->set_name ("lock button");
7846 b->set_text (_("Click to unlock"));
7847 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7848 lock_dialog->get_vbox()->pack_start (*b);
7850 lock_dialog->get_vbox()->show_all ();
7851 lock_dialog->set_size_request (200, 200);
7854 delete _main_menu_disabler;
7855 _main_menu_disabler = new MainMenuDisabler;
7857 lock_dialog->present ();
7863 lock_dialog->hide ();
7865 delete _main_menu_disabler;
7866 _main_menu_disabler = 0;
7868 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7869 start_lock_event_timing ();
7874 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7876 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7880 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7882 Timers::TimerSuspender t;
7883 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7884 Gtkmm2ext::UI::instance()->flush_pending ();
7888 Editor::bring_all_sources_into_session ()
7895 ArdourDialog w (_("Moving embedded files into session folder"));
7896 w.get_vbox()->pack_start (msg);
7899 /* flush all pending GUI events because we're about to start copying
7903 Timers::TimerSuspender t;
7904 Gtkmm2ext::UI::instance()->flush_pending ();
7908 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));