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) const
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());
5170 apply_filter (s, _("strip silence"), &d);
5175 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5177 Evoral::Sequence<Evoral::Beats>::Notes selected;
5178 mrv.selection_as_notelist (selected, true);
5180 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5181 v.push_back (selected);
5183 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5184 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5186 return op (mrv.midi_region()->model(), pos_beats, v);
5190 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5196 bool in_command = false;
5198 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5199 RegionSelection::const_iterator tmp = r;
5202 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5205 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5208 begin_reversible_command (op.name ());
5212 _session->add_command (cmd);
5220 commit_reversible_command ();
5225 Editor::fork_region ()
5227 RegionSelection rs = get_regions_from_selection_and_entered ();
5233 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5234 bool in_command = false;
5238 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5239 RegionSelection::iterator tmp = r;
5242 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5246 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5247 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5248 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5251 begin_reversible_command (_("Fork Region(s)"));
5254 playlist->clear_changes ();
5255 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5256 _session->add_command(new StatefulDiffCommand (playlist));
5258 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5266 commit_reversible_command ();
5271 Editor::quantize_region ()
5274 quantize_regions(get_regions_from_selection_and_entered ());
5279 Editor::quantize_regions (const RegionSelection& rs)
5281 if (rs.n_midi_regions() == 0) {
5285 if (!quantize_dialog) {
5286 quantize_dialog = new QuantizeDialog (*this);
5289 quantize_dialog->present ();
5290 const int r = quantize_dialog->run ();
5291 quantize_dialog->hide ();
5293 if (r == Gtk::RESPONSE_OK) {
5294 Quantize quant (quantize_dialog->snap_start(),
5295 quantize_dialog->snap_end(),
5296 quantize_dialog->start_grid_size(),
5297 quantize_dialog->end_grid_size(),
5298 quantize_dialog->strength(),
5299 quantize_dialog->swing(),
5300 quantize_dialog->threshold());
5302 apply_midi_note_edit_op (quant, rs);
5307 Editor::legatize_region (bool shrink_only)
5310 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5315 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5317 if (rs.n_midi_regions() == 0) {
5321 Legatize legatize(shrink_only);
5322 apply_midi_note_edit_op (legatize, rs);
5326 Editor::transform_region ()
5329 transform_regions(get_regions_from_selection_and_entered ());
5334 Editor::transform_regions (const RegionSelection& rs)
5336 if (rs.n_midi_regions() == 0) {
5343 const int r = td.run();
5346 if (r == Gtk::RESPONSE_OK) {
5347 Transform transform(td.get());
5348 apply_midi_note_edit_op(transform, rs);
5353 Editor::transpose_region ()
5356 transpose_regions(get_regions_from_selection_and_entered ());
5361 Editor::transpose_regions (const RegionSelection& rs)
5363 if (rs.n_midi_regions() == 0) {
5368 int const r = d.run ();
5370 if (r == RESPONSE_ACCEPT) {
5371 Transpose transpose(d.semitones ());
5372 apply_midi_note_edit_op (transpose, rs);
5377 Editor::insert_patch_change (bool from_context)
5379 RegionSelection rs = get_regions_from_selection_and_entered ();
5385 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5387 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5388 there may be more than one, but the PatchChangeDialog can only offer
5389 one set of patch menus.
5391 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5393 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5394 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5396 if (d.run() == RESPONSE_CANCEL) {
5400 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5401 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5403 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5404 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5411 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5413 RegionSelection rs = get_regions_from_selection_and_entered ();
5419 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5420 bool in_command = false;
5425 int const N = rs.size ();
5427 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5428 RegionSelection::iterator tmp = r;
5431 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5433 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5436 progress->descend (1.0 / N);
5439 if (arv->audio_region()->apply (filter, progress) == 0) {
5441 playlist->clear_changes ();
5442 playlist->clear_owned_changes ();
5445 begin_reversible_command (command);
5449 if (filter.results.empty ()) {
5451 /* no regions returned; remove the old one */
5452 playlist->remove_region (arv->region ());
5456 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5458 /* first region replaces the old one */
5459 playlist->replace_region (arv->region(), *res, (*res)->position());
5463 while (res != filter.results.end()) {
5464 playlist->add_region (*res, (*res)->position());
5470 /* We might have removed regions, which alters other regions' layering_index,
5471 so we need to do a recursive diff here.
5473 vector<Command*> cmds;
5474 playlist->rdiff (cmds);
5475 _session->add_commands (cmds);
5477 _session->add_command(new StatefulDiffCommand (playlist));
5481 progress->ascend ();
5490 commit_reversible_command ();
5495 Editor::external_edit_region ()
5501 Editor::reset_region_gain_envelopes ()
5503 RegionSelection rs = get_regions_from_selection_and_entered ();
5505 if (!_session || rs.empty()) {
5509 bool in_command = false;
5511 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5512 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5514 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5515 XMLNode& before (alist->get_state());
5517 arv->audio_region()->set_default_envelope ();
5520 begin_reversible_command (_("reset region gain"));
5523 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5528 commit_reversible_command ();
5533 Editor::set_region_gain_visibility (RegionView* rv)
5535 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5537 arv->update_envelope_visibility();
5542 Editor::set_gain_envelope_visibility ()
5548 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5549 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5551 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5557 Editor::toggle_gain_envelope_active ()
5559 if (_ignore_region_action) {
5563 RegionSelection rs = get_regions_from_selection_and_entered ();
5565 if (!_session || rs.empty()) {
5569 bool in_command = false;
5571 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5572 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5574 arv->region()->clear_changes ();
5575 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5578 begin_reversible_command (_("region gain envelope active"));
5581 _session->add_command (new StatefulDiffCommand (arv->region()));
5586 commit_reversible_command ();
5591 Editor::toggle_region_lock ()
5593 if (_ignore_region_action) {
5597 RegionSelection rs = get_regions_from_selection_and_entered ();
5599 if (!_session || rs.empty()) {
5603 begin_reversible_command (_("toggle region lock"));
5605 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5606 (*i)->region()->clear_changes ();
5607 (*i)->region()->set_locked (!(*i)->region()->locked());
5608 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5611 commit_reversible_command ();
5615 Editor::toggle_region_video_lock ()
5617 if (_ignore_region_action) {
5621 RegionSelection rs = get_regions_from_selection_and_entered ();
5623 if (!_session || rs.empty()) {
5627 begin_reversible_command (_("Toggle Video Lock"));
5629 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5630 (*i)->region()->clear_changes ();
5631 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5632 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5635 commit_reversible_command ();
5639 Editor::toggle_region_lock_style ()
5641 if (_ignore_region_action) {
5645 RegionSelection rs = get_regions_from_selection_and_entered ();
5647 if (!_session || rs.empty()) {
5651 begin_reversible_command (_("region lock style"));
5653 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5654 (*i)->region()->clear_changes ();
5655 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5656 (*i)->region()->set_position_lock_style (ns);
5657 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5660 commit_reversible_command ();
5664 Editor::toggle_opaque_region ()
5666 if (_ignore_region_action) {
5670 RegionSelection rs = get_regions_from_selection_and_entered ();
5672 if (!_session || rs.empty()) {
5676 begin_reversible_command (_("change region opacity"));
5678 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5679 (*i)->region()->clear_changes ();
5680 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5681 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5684 commit_reversible_command ();
5688 Editor::toggle_record_enable ()
5690 bool new_state = false;
5692 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5693 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5696 if (!rtav->is_track())
5700 new_state = !rtav->track()->record_enabled();
5704 rtav->track()->set_record_enabled (new_state, Controllable::UseGroup);
5709 Editor::toggle_solo ()
5711 bool new_state = false;
5713 boost::shared_ptr<RouteList> rl (new RouteList);
5715 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5716 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5723 new_state = !rtav->route()->soloed ();
5727 rl->push_back (rtav->route());
5730 _session->set_solo (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
5734 Editor::toggle_mute ()
5736 bool new_state = false;
5738 boost::shared_ptr<RouteList> rl (new RouteList);
5740 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5741 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5748 new_state = !rtav->route()->muted();
5752 rl->push_back (rtav->route());
5755 _session->set_mute (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
5759 Editor::toggle_solo_isolate ()
5765 Editor::fade_range ()
5767 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5769 begin_reversible_command (_("fade range"));
5771 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5772 (*i)->fade_range (selection->time);
5775 commit_reversible_command ();
5780 Editor::set_fade_length (bool in)
5782 RegionSelection rs = get_regions_from_selection_and_entered ();
5788 /* we need a region to measure the offset from the start */
5790 RegionView* rv = rs.front ();
5792 framepos_t pos = get_preferred_edit_position();
5796 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5797 /* edit point is outside the relevant region */
5802 if (pos <= rv->region()->position()) {
5806 len = pos - rv->region()->position();
5807 cmd = _("set fade in length");
5809 if (pos >= rv->region()->last_frame()) {
5813 len = rv->region()->last_frame() - pos;
5814 cmd = _("set fade out length");
5817 bool in_command = false;
5819 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5820 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5826 boost::shared_ptr<AutomationList> alist;
5828 alist = tmp->audio_region()->fade_in();
5830 alist = tmp->audio_region()->fade_out();
5833 XMLNode &before = alist->get_state();
5836 tmp->audio_region()->set_fade_in_length (len);
5837 tmp->audio_region()->set_fade_in_active (true);
5839 tmp->audio_region()->set_fade_out_length (len);
5840 tmp->audio_region()->set_fade_out_active (true);
5844 begin_reversible_command (cmd);
5847 XMLNode &after = alist->get_state();
5848 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5852 commit_reversible_command ();
5857 Editor::set_fade_in_shape (FadeShape shape)
5859 RegionSelection rs = get_regions_from_selection_and_entered ();
5864 bool in_command = false;
5866 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5867 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5873 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5874 XMLNode &before = alist->get_state();
5876 tmp->audio_region()->set_fade_in_shape (shape);
5879 begin_reversible_command (_("set fade in shape"));
5882 XMLNode &after = alist->get_state();
5883 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5887 commit_reversible_command ();
5892 Editor::set_fade_out_shape (FadeShape shape)
5894 RegionSelection rs = get_regions_from_selection_and_entered ();
5899 bool in_command = false;
5901 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5902 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5908 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5909 XMLNode &before = alist->get_state();
5911 tmp->audio_region()->set_fade_out_shape (shape);
5914 begin_reversible_command (_("set fade out shape"));
5917 XMLNode &after = alist->get_state();
5918 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5922 commit_reversible_command ();
5927 Editor::set_fade_in_active (bool yn)
5929 RegionSelection rs = get_regions_from_selection_and_entered ();
5934 bool in_command = false;
5936 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5937 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5944 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5946 ar->clear_changes ();
5947 ar->set_fade_in_active (yn);
5950 begin_reversible_command (_("set fade in active"));
5953 _session->add_command (new StatefulDiffCommand (ar));
5957 commit_reversible_command ();
5962 Editor::set_fade_out_active (bool yn)
5964 RegionSelection rs = get_regions_from_selection_and_entered ();
5969 bool in_command = false;
5971 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5972 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5978 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5980 ar->clear_changes ();
5981 ar->set_fade_out_active (yn);
5984 begin_reversible_command (_("set fade out active"));
5987 _session->add_command(new StatefulDiffCommand (ar));
5991 commit_reversible_command ();
5996 Editor::toggle_region_fades (int dir)
5998 if (_ignore_region_action) {
6002 boost::shared_ptr<AudioRegion> ar;
6005 RegionSelection rs = get_regions_from_selection_and_entered ();
6011 RegionSelection::iterator i;
6012 for (i = rs.begin(); i != rs.end(); ++i) {
6013 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6015 yn = ar->fade_out_active ();
6017 yn = ar->fade_in_active ();
6023 if (i == rs.end()) {
6027 /* XXX should this undo-able? */
6028 bool in_command = false;
6030 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6031 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6034 ar->clear_changes ();
6036 if (dir == 1 || dir == 0) {
6037 ar->set_fade_in_active (!yn);
6040 if (dir == -1 || dir == 0) {
6041 ar->set_fade_out_active (!yn);
6044 begin_reversible_command (_("toggle fade active"));
6047 _session->add_command(new StatefulDiffCommand (ar));
6051 commit_reversible_command ();
6056 /** Update region fade visibility after its configuration has been changed */
6058 Editor::update_region_fade_visibility ()
6060 bool _fade_visibility = _session->config.get_show_region_fades ();
6062 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6063 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6065 if (_fade_visibility) {
6066 v->audio_view()->show_all_fades ();
6068 v->audio_view()->hide_all_fades ();
6075 Editor::set_edit_point ()
6080 if (!mouse_frame (where, ignored)) {
6086 if (selection->markers.empty()) {
6088 mouse_add_new_marker (where);
6093 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6096 loc->move_to (where);
6102 Editor::set_playhead_cursor ()
6104 if (entered_marker) {
6105 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6110 if (!mouse_frame (where, ignored)) {
6117 _session->request_locate (where, _session->transport_rolling());
6121 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6122 cancel_time_selection();
6127 Editor::split_region ()
6129 if (_drags->active ()) {
6133 //if a range is selected, separate it
6134 if ( !selection->time.empty()) {
6135 separate_regions_between (selection->time);
6139 //if no range was selected, try to find some regions to split
6140 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6142 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6144 framepos_t where = get_preferred_edit_position ();
6150 split_regions_at (where, rs);
6154 struct EditorOrderRouteSorter {
6155 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6156 return a->order_key () < b->order_key ();
6161 Editor::select_next_route()
6163 if (selection->tracks.empty()) {
6164 selection->set (track_views.front());
6168 TimeAxisView* current = selection->tracks.front();
6172 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6173 if (*i == current) {
6175 if (i != track_views.end()) {
6178 current = (*(track_views.begin()));
6179 //selection->set (*(track_views.begin()));
6184 rui = dynamic_cast<RouteUI *>(current);
6185 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6187 selection->set(current);
6189 ensure_time_axis_view_is_visible (*current, false);
6193 Editor::select_prev_route()
6195 if (selection->tracks.empty()) {
6196 selection->set (track_views.front());
6200 TimeAxisView* current = selection->tracks.front();
6204 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6205 if (*i == current) {
6207 if (i != track_views.rend()) {
6210 current = *(track_views.rbegin());
6215 rui = dynamic_cast<RouteUI *>(current);
6216 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6218 selection->set (current);
6220 ensure_time_axis_view_is_visible (*current, false);
6224 Editor::set_loop_from_selection (bool play)
6226 if (_session == 0) {
6230 framepos_t start, end;
6231 if (!get_selection_extents ( start, end))
6234 set_loop_range (start, end, _("set loop range from selection"));
6237 _session->request_play_loop (true, true);
6242 Editor::set_loop_from_region (bool play)
6244 framepos_t start, end;
6245 if (!get_selection_extents ( start, end))
6248 set_loop_range (start, end, _("set loop range from region"));
6251 _session->request_locate (start, true);
6252 _session->request_play_loop (true);
6257 Editor::set_punch_from_selection ()
6259 if (_session == 0) {
6263 framepos_t start, end;
6264 if (!get_selection_extents ( start, end))
6267 set_punch_range (start, end, _("set punch range from selection"));
6271 Editor::set_session_extents_from_selection ()
6273 if (_session == 0) {
6277 framepos_t start, end;
6278 if (!get_selection_extents ( start, end))
6282 if ((loc = _session->locations()->session_range_location()) == 0) {
6283 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6285 XMLNode &before = loc->get_state();
6287 _session->set_session_extents ( start, end );
6289 XMLNode &after = loc->get_state();
6291 begin_reversible_command (_("set session start/end from selection"));
6293 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6295 commit_reversible_command ();
6300 Editor::set_punch_start_from_edit_point ()
6304 framepos_t start = 0;
6305 framepos_t end = max_framepos;
6307 //use the existing punch end, if any
6308 Location* tpl = transport_punch_location();
6313 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6314 start = _session->audible_frame();
6316 start = get_preferred_edit_position();
6319 //snap the selection start/end
6322 //if there's not already a sensible selection endpoint, go "forever"
6323 if ( start > end ) {
6327 set_punch_range (start, end, _("set punch start from EP"));
6333 Editor::set_punch_end_from_edit_point ()
6337 framepos_t start = 0;
6338 framepos_t end = max_framepos;
6340 //use the existing punch start, if any
6341 Location* tpl = transport_punch_location();
6343 start = tpl->start();
6346 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6347 end = _session->audible_frame();
6349 end = get_preferred_edit_position();
6352 //snap the selection start/end
6355 set_punch_range (start, end, _("set punch end from EP"));
6361 Editor::set_loop_start_from_edit_point ()
6365 framepos_t start = 0;
6366 framepos_t end = max_framepos;
6368 //use the existing loop end, if any
6369 Location* tpl = transport_loop_location();
6374 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6375 start = _session->audible_frame();
6377 start = get_preferred_edit_position();
6380 //snap the selection start/end
6383 //if there's not already a sensible selection endpoint, go "forever"
6384 if ( start > end ) {
6388 set_loop_range (start, end, _("set loop start from EP"));
6394 Editor::set_loop_end_from_edit_point ()
6398 framepos_t start = 0;
6399 framepos_t end = max_framepos;
6401 //use the existing loop start, if any
6402 Location* tpl = transport_loop_location();
6404 start = tpl->start();
6407 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6408 end = _session->audible_frame();
6410 end = get_preferred_edit_position();
6413 //snap the selection start/end
6416 set_loop_range (start, end, _("set loop end from EP"));
6421 Editor::set_punch_from_region ()
6423 framepos_t start, end;
6424 if (!get_selection_extents ( start, end))
6427 set_punch_range (start, end, _("set punch range from region"));
6431 Editor::pitch_shift_region ()
6433 RegionSelection rs = get_regions_from_selection_and_entered ();
6435 RegionSelection audio_rs;
6436 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6437 if (dynamic_cast<AudioRegionView*> (*i)) {
6438 audio_rs.push_back (*i);
6442 if (audio_rs.empty()) {
6446 pitch_shift (audio_rs, 1.2);
6450 Editor::set_tempo_from_region ()
6452 RegionSelection rs = get_regions_from_selection_and_entered ();
6454 if (!_session || rs.empty()) {
6458 RegionView* rv = rs.front();
6460 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6464 Editor::use_range_as_bar ()
6466 framepos_t start, end;
6467 if (get_edit_op_range (start, end)) {
6468 define_one_bar (start, end);
6473 Editor::define_one_bar (framepos_t start, framepos_t end)
6475 framepos_t length = end - start;
6477 const Meter& m (_session->tempo_map().meter_at (start));
6479 /* length = 1 bar */
6481 /* now we want frames per beat.
6482 we have frames per bar, and beats per bar, so ...
6485 /* XXXX METER MATH */
6487 double frames_per_beat = length / m.divisions_per_bar();
6489 /* beats per minute = */
6491 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6493 /* now decide whether to:
6495 (a) set global tempo
6496 (b) add a new tempo marker
6500 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6502 bool do_global = false;
6504 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6506 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6507 at the start, or create a new marker
6510 vector<string> options;
6511 options.push_back (_("Cancel"));
6512 options.push_back (_("Add new marker"));
6513 options.push_back (_("Set global tempo"));
6516 _("Define one bar"),
6517 _("Do you want to set the global tempo or add a new tempo marker?"),
6521 c.set_default_response (2);
6537 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6538 if the marker is at the region starter, change it, otherwise add
6543 begin_reversible_command (_("set tempo from region"));
6544 XMLNode& before (_session->tempo_map().get_state());
6547 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6548 } else if (t.frame() == start) {
6549 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6551 Timecode::BBT_Time bbt;
6552 _session->tempo_map().bbt_time (start, bbt);
6553 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6556 XMLNode& after (_session->tempo_map().get_state());
6558 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6559 commit_reversible_command ();
6563 Editor::split_region_at_transients ()
6565 AnalysisFeatureList positions;
6567 RegionSelection rs = get_regions_from_selection_and_entered ();
6569 if (!_session || rs.empty()) {
6573 begin_reversible_command (_("split regions"));
6575 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6577 RegionSelection::iterator tmp;
6582 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6584 if (ar && (ar->get_transients (positions) == 0)) {
6585 split_region_at_points ((*i)->region(), positions, true);
6592 commit_reversible_command ();
6597 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6599 bool use_rhythmic_rodent = false;
6601 boost::shared_ptr<Playlist> pl = r->playlist();
6603 list<boost::shared_ptr<Region> > new_regions;
6609 if (positions.empty()) {
6614 if (positions.size() > 20 && can_ferret) {
6615 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);
6616 MessageDialog msg (msgstr,
6619 Gtk::BUTTONS_OK_CANCEL);
6622 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6623 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6625 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6628 msg.set_title (_("Excessive split?"));
6631 int response = msg.run();
6637 case RESPONSE_APPLY:
6638 use_rhythmic_rodent = true;
6645 if (use_rhythmic_rodent) {
6646 show_rhythm_ferret ();
6650 AnalysisFeatureList::const_iterator x;
6652 pl->clear_changes ();
6653 pl->clear_owned_changes ();
6655 x = positions.begin();
6657 if (x == positions.end()) {
6662 pl->remove_region (r);
6666 while (x != positions.end()) {
6668 /* deal with positons that are out of scope of present region bounds */
6669 if (*x <= 0 || *x > r->length()) {
6674 /* file start = original start + how far we from the initial position ?
6677 framepos_t file_start = r->start() + pos;
6679 /* length = next position - current position
6682 framepos_t len = (*x) - pos;
6684 /* XXX we do we really want to allow even single-sample regions?
6685 shouldn't we have some kind of lower limit on region size?
6694 if (RegionFactory::region_name (new_name, r->name())) {
6698 /* do NOT announce new regions 1 by one, just wait till they are all done */
6702 plist.add (ARDOUR::Properties::start, file_start);
6703 plist.add (ARDOUR::Properties::length, len);
6704 plist.add (ARDOUR::Properties::name, new_name);
6705 plist.add (ARDOUR::Properties::layer, 0);
6707 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6708 /* because we set annouce to false, manually add the new region to the
6711 RegionFactory::map_add (nr);
6713 pl->add_region (nr, r->position() + pos);
6716 new_regions.push_front(nr);
6725 RegionFactory::region_name (new_name, r->name());
6727 /* Add the final region */
6730 plist.add (ARDOUR::Properties::start, r->start() + pos);
6731 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6732 plist.add (ARDOUR::Properties::name, new_name);
6733 plist.add (ARDOUR::Properties::layer, 0);
6735 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6736 /* because we set annouce to false, manually add the new region to the
6739 RegionFactory::map_add (nr);
6740 pl->add_region (nr, r->position() + pos);
6743 new_regions.push_front(nr);
6748 /* We might have removed regions, which alters other regions' layering_index,
6749 so we need to do a recursive diff here.
6751 vector<Command*> cmds;
6753 _session->add_commands (cmds);
6755 _session->add_command (new StatefulDiffCommand (pl));
6759 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6760 set_selected_regionview_from_region_list ((*i), Selection::Add);
6766 Editor::place_transient()
6772 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6778 framepos_t where = get_preferred_edit_position();
6780 begin_reversible_command (_("place transient"));
6782 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6783 framepos_t position = (*r)->region()->position();
6784 (*r)->region()->add_transient(where - position);
6787 commit_reversible_command ();
6791 Editor::remove_transient(ArdourCanvas::Item* item)
6797 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6800 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6801 _arv->remove_transient (*(float*) _line->get_data ("position"));
6805 Editor::snap_regions_to_grid ()
6807 list <boost::shared_ptr<Playlist > > used_playlists;
6809 RegionSelection rs = get_regions_from_selection_and_entered ();
6811 if (!_session || rs.empty()) {
6815 begin_reversible_command (_("snap regions to grid"));
6817 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6819 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6821 if (!pl->frozen()) {
6822 /* we haven't seen this playlist before */
6824 /* remember used playlists so we can thaw them later */
6825 used_playlists.push_back(pl);
6829 framepos_t start_frame = (*r)->region()->first_frame ();
6830 snap_to (start_frame);
6831 (*r)->region()->set_position (start_frame);
6834 while (used_playlists.size() > 0) {
6835 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6837 used_playlists.pop_front();
6840 commit_reversible_command ();
6844 Editor::close_region_gaps ()
6846 list <boost::shared_ptr<Playlist > > used_playlists;
6848 RegionSelection rs = get_regions_from_selection_and_entered ();
6850 if (!_session || rs.empty()) {
6854 Dialog dialog (_("Close Region Gaps"));
6857 table.set_spacings (12);
6858 table.set_border_width (12);
6859 Label* l = manage (left_aligned_label (_("Crossfade length")));
6860 table.attach (*l, 0, 1, 0, 1);
6862 SpinButton spin_crossfade (1, 0);
6863 spin_crossfade.set_range (0, 15);
6864 spin_crossfade.set_increments (1, 1);
6865 spin_crossfade.set_value (5);
6866 table.attach (spin_crossfade, 1, 2, 0, 1);
6868 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6870 l = manage (left_aligned_label (_("Pull-back length")));
6871 table.attach (*l, 0, 1, 1, 2);
6873 SpinButton spin_pullback (1, 0);
6874 spin_pullback.set_range (0, 100);
6875 spin_pullback.set_increments (1, 1);
6876 spin_pullback.set_value(30);
6877 table.attach (spin_pullback, 1, 2, 1, 2);
6879 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6881 dialog.get_vbox()->pack_start (table);
6882 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6883 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6886 if (dialog.run () == RESPONSE_CANCEL) {
6890 framepos_t crossfade_len = spin_crossfade.get_value();
6891 framepos_t pull_back_frames = spin_pullback.get_value();
6893 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6894 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6896 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6898 begin_reversible_command (_("close region gaps"));
6901 boost::shared_ptr<Region> last_region;
6903 rs.sort_by_position_and_track();
6905 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6907 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6909 if (!pl->frozen()) {
6910 /* we haven't seen this playlist before */
6912 /* remember used playlists so we can thaw them later */
6913 used_playlists.push_back(pl);
6917 framepos_t position = (*r)->region()->position();
6919 if (idx == 0 || position < last_region->position()){
6920 last_region = (*r)->region();
6925 (*r)->region()->trim_front( (position - pull_back_frames));
6926 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6928 last_region = (*r)->region();
6933 while (used_playlists.size() > 0) {
6934 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6936 used_playlists.pop_front();
6939 commit_reversible_command ();
6943 Editor::tab_to_transient (bool forward)
6945 AnalysisFeatureList positions;
6947 RegionSelection rs = get_regions_from_selection_and_entered ();
6953 framepos_t pos = _session->audible_frame ();
6955 if (!selection->tracks.empty()) {
6957 /* don't waste time searching for transients in duplicate playlists.
6960 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6962 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6964 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6967 boost::shared_ptr<Track> tr = rtv->track();
6969 boost::shared_ptr<Playlist> pl = tr->playlist ();
6971 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6974 positions.push_back (result);
6987 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6988 (*r)->region()->get_transients (positions);
6992 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6995 AnalysisFeatureList::iterator x;
6997 for (x = positions.begin(); x != positions.end(); ++x) {
7003 if (x != positions.end ()) {
7004 _session->request_locate (*x);
7008 AnalysisFeatureList::reverse_iterator x;
7010 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7016 if (x != positions.rend ()) {
7017 _session->request_locate (*x);
7023 Editor::playhead_forward_to_grid ()
7029 framepos_t pos = playhead_cursor->current_frame ();
7030 if (pos < max_framepos - 1) {
7032 snap_to_internal (pos, RoundUpAlways, false);
7033 _session->request_locate (pos);
7039 Editor::playhead_backward_to_grid ()
7045 framepos_t pos = playhead_cursor->current_frame ();
7048 snap_to_internal (pos, RoundDownAlways, false);
7049 _session->request_locate (pos);
7054 Editor::set_track_height (Height h)
7056 TrackSelection& ts (selection->tracks);
7058 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7059 (*x)->set_height_enum (h);
7064 Editor::toggle_tracks_active ()
7066 TrackSelection& ts (selection->tracks);
7068 bool target = false;
7074 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7075 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7079 target = !rtv->_route->active();
7082 rtv->_route->set_active (target, this);
7088 Editor::remove_tracks ()
7090 /* this will delete GUI objects that may be the subject of an event
7091 handler in which this method is called. Defer actual deletion to the
7092 next idle callback, when all event handling is finished.
7094 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7098 Editor::idle_remove_tracks ()
7101 return false; /* do not call again */
7105 Editor::_remove_tracks ()
7107 TrackSelection& ts (selection->tracks);
7113 vector<string> choices;
7117 const char* trackstr;
7119 vector<boost::shared_ptr<Route> > routes;
7120 bool special_bus = false;
7122 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7123 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7127 if (rtv->is_track()) {
7132 routes.push_back (rtv->_route);
7134 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7139 if (special_bus && !Config->get_allow_special_bus_removal()) {
7140 MessageDialog msg (_("That would be bad news ...."),
7144 msg.set_secondary_text (string_compose (_(
7145 "Removing the master or monitor bus is such a bad idea\n\
7146 that %1 is not going to allow it.\n\
7148 If you really want to do this sort of thing\n\
7149 edit your ardour.rc file to set the\n\
7150 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7157 if (ntracks + nbusses == 0) {
7161 trackstr = P_("track", "tracks", ntracks);
7162 busstr = P_("bus", "busses", nbusses);
7166 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7167 "(You may also lose the playlists associated with the %2)\n\n"
7168 "This action cannot be undone, and the session file will be overwritten!"),
7169 ntracks, trackstr, nbusses, busstr);
7171 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7172 "(You may also lose the playlists associated with the %2)\n\n"
7173 "This action cannot be undone, and the session file will be overwritten!"),
7176 } else if (nbusses) {
7177 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7178 "This action cannot be undone, and the session file will be overwritten"),
7182 choices.push_back (_("No, do nothing."));
7183 if (ntracks + nbusses > 1) {
7184 choices.push_back (_("Yes, remove them."));
7186 choices.push_back (_("Yes, remove it."));
7191 title = string_compose (_("Remove %1"), trackstr);
7193 title = string_compose (_("Remove %1"), busstr);
7196 Choice prompter (title, prompt, choices);
7198 if (prompter.run () != 1) {
7203 Session::StateProtector sp (_session);
7204 DisplaySuspender ds;
7205 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7206 _session->remove_route (*x);
7212 Editor::do_insert_time ()
7214 if (selection->tracks.empty()) {
7218 InsertRemoveTimeDialog d (*this);
7219 int response = d.run ();
7221 if (response != RESPONSE_OK) {
7225 if (d.distance() == 0) {
7230 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7232 d.intersected_region_action (),
7236 d.move_glued_markers(),
7237 d.move_locked_markers(),
7243 Editor::insert_time (
7244 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7245 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7249 if (Config->get_edit_mode() == Lock) {
7252 bool in_command = false;
7254 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7256 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7260 /* don't operate on any playlist more than once, which could
7261 * happen if "all playlists" is enabled, but there is more
7262 * than 1 track using playlists "from" a given track.
7265 set<boost::shared_ptr<Playlist> > pl;
7267 if (all_playlists) {
7268 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7269 if (rtav && rtav->track ()) {
7270 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7271 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7276 if ((*x)->playlist ()) {
7277 pl.insert ((*x)->playlist ());
7281 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7283 (*i)->clear_changes ();
7284 (*i)->clear_owned_changes ();
7286 if (opt == SplitIntersected) {
7290 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7293 begin_reversible_command (_("insert time"));
7296 vector<Command*> cmds;
7298 _session->add_commands (cmds);
7300 _session->add_command (new StatefulDiffCommand (*i));
7304 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7307 begin_reversible_command (_("insert time"));
7310 rtav->route ()->shift (pos, frames);
7317 XMLNode& before (_session->locations()->get_state());
7318 Locations::LocationList copy (_session->locations()->list());
7320 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7322 Locations::LocationList::const_iterator tmp;
7324 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7325 bool const was_locked = (*i)->locked ();
7326 if (locked_markers_too) {
7330 if ((*i)->start() >= pos) {
7331 // move end first, in case we're moving by more than the length of the range
7332 if (!(*i)->is_mark()) {
7333 (*i)->set_end ((*i)->end() + frames);
7335 (*i)->set_start ((*i)->start() + frames);
7347 begin_reversible_command (_("insert time"));
7350 XMLNode& after (_session->locations()->get_state());
7351 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7357 begin_reversible_command (_("insert time"));
7360 XMLNode& before (_session->tempo_map().get_state());
7361 _session->tempo_map().insert_time (pos, frames);
7362 XMLNode& after (_session->tempo_map().get_state());
7363 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7367 commit_reversible_command ();
7372 Editor::do_remove_time ()
7374 if (selection->tracks.empty()) {
7378 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7379 InsertRemoveTimeDialog d (*this, true);
7381 int response = d.run ();
7383 if (response != RESPONSE_OK) {
7387 framecnt_t distance = d.distance();
7389 if (distance == 0) {
7399 d.move_glued_markers(),
7400 d.move_locked_markers(),
7406 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7407 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7409 if (Config->get_edit_mode() == Lock) {
7410 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7413 bool in_command = false;
7415 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7417 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7421 XMLNode &before = pl->get_state();
7423 std::list<AudioRange> rl;
7424 AudioRange ar(pos, pos+frames, 0);
7427 pl->shift (pos, -frames, true, ignore_music_glue);
7430 begin_reversible_command (_("remove time"));
7433 XMLNode &after = pl->get_state();
7435 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7439 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7442 begin_reversible_command (_("remove time"));
7445 rtav->route ()->shift (pos, -frames);
7449 std::list<Location*> loc_kill_list;
7454 XMLNode& before (_session->locations()->get_state());
7455 Locations::LocationList copy (_session->locations()->list());
7457 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7458 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7460 bool const was_locked = (*i)->locked ();
7461 if (locked_markers_too) {
7465 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7466 if ((*i)->end() >= pos
7467 && (*i)->end() < pos+frames
7468 && (*i)->start() >= pos
7469 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7471 loc_kill_list.push_back(*i);
7472 } else { // only start or end is included, try to do the right thing
7473 // move start before moving end, to avoid trying to move the end to before the start
7474 // if we're removing more time than the length of the range
7475 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7476 // start is within cut
7477 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7479 } else if ((*i)->start() >= pos+frames) {
7480 // start (and thus entire range) lies beyond end of cut
7481 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7484 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7485 // end is inside cut
7486 (*i)->set_end (pos); // bring the end to the cut
7488 } else if ((*i)->end() >= pos+frames) {
7489 // end is beyond end of cut
7490 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7495 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7496 loc_kill_list.push_back(*i);
7498 } else if ((*i)->start() >= pos) {
7499 (*i)->set_start ((*i)->start() -frames);
7509 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7510 _session->locations()->remove( *i );
7515 begin_reversible_command (_("remove time"));
7518 XMLNode& after (_session->locations()->get_state());
7519 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7524 XMLNode& before (_session->tempo_map().get_state());
7526 if (_session->tempo_map().remove_time (pos, frames) ) {
7528 begin_reversible_command (_("remove time"));
7531 XMLNode& after (_session->tempo_map().get_state());
7532 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7537 commit_reversible_command ();
7542 Editor::fit_selection ()
7544 if (!selection->tracks.empty()) {
7545 fit_tracks (selection->tracks);
7549 /* no selected tracks - use tracks with selected regions */
7551 if (!selection->regions.empty()) {
7552 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7553 tvl.push_back (&(*r)->get_time_axis_view ());
7559 } else if (internal_editing()) {
7560 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7563 if (entered_track) {
7564 tvl.push_back (entered_track);
7573 Editor::fit_tracks (TrackViewList & tracks)
7575 if (tracks.empty()) {
7579 uint32_t child_heights = 0;
7580 int visible_tracks = 0;
7582 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7584 if (!(*t)->marked_for_display()) {
7588 child_heights += (*t)->effective_height() - (*t)->current_height();
7592 /* compute the per-track height from:
7594 total canvas visible height -
7595 height that will be taken by visible children of selected
7596 tracks - height of the ruler/hscroll area
7598 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7599 double first_y_pos = DBL_MAX;
7601 if (h < TimeAxisView::preset_height (HeightSmall)) {
7602 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7603 /* too small to be displayed */
7607 undo_visual_stack.push_back (current_visual_state (true));
7608 PBD::Unwinder<bool> nsv (no_save_visual, true);
7610 /* build a list of all tracks, including children */
7613 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7615 TimeAxisView::Children c = (*i)->get_child_list ();
7616 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7617 all.push_back (j->get());
7622 // find selection range.
7623 // if someone knows how to user TrackViewList::iterator for this
7625 int selected_top = -1;
7626 int selected_bottom = -1;
7628 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7629 if ((*t)->marked_for_display ()) {
7630 if (tracks.contains(*t)) {
7631 if (selected_top == -1) {
7634 selected_bottom = i;
7640 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7641 if ((*t)->marked_for_display ()) {
7642 if (tracks.contains(*t)) {
7643 (*t)->set_height (h);
7644 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7646 if (i > selected_top && i < selected_bottom) {
7647 hide_track_in_display (*t);
7654 set the controls_layout height now, because waiting for its size
7655 request signal handler will cause the vertical adjustment setting to fail
7658 controls_layout.property_height () = _full_canvas_height;
7659 vertical_adjustment.set_value (first_y_pos);
7661 redo_visual_stack.push_back (current_visual_state (true));
7663 visible_tracks_selector.set_text (_("Sel"));
7667 Editor::save_visual_state (uint32_t n)
7669 while (visual_states.size() <= n) {
7670 visual_states.push_back (0);
7673 if (visual_states[n] != 0) {
7674 delete visual_states[n];
7677 visual_states[n] = current_visual_state (true);
7682 Editor::goto_visual_state (uint32_t n)
7684 if (visual_states.size() <= n) {
7688 if (visual_states[n] == 0) {
7692 use_visual_state (*visual_states[n]);
7696 Editor::start_visual_state_op (uint32_t n)
7698 save_visual_state (n);
7700 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7702 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7703 pup->set_text (buf);
7708 Editor::cancel_visual_state_op (uint32_t n)
7710 goto_visual_state (n);
7714 Editor::toggle_region_mute ()
7716 if (_ignore_region_action) {
7720 RegionSelection rs = get_regions_from_selection_and_entered ();
7726 if (rs.size() > 1) {
7727 begin_reversible_command (_("mute regions"));
7729 begin_reversible_command (_("mute region"));
7732 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7734 (*i)->region()->playlist()->clear_changes ();
7735 (*i)->region()->set_muted (!(*i)->region()->muted ());
7736 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7740 commit_reversible_command ();
7744 Editor::combine_regions ()
7746 /* foreach track with selected regions, take all selected regions
7747 and join them into a new region containing the subregions (as a
7751 typedef set<RouteTimeAxisView*> RTVS;
7754 if (selection->regions.empty()) {
7758 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7759 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7762 tracks.insert (rtv);
7766 begin_reversible_command (_("combine regions"));
7768 vector<RegionView*> new_selection;
7770 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7773 if ((rv = (*i)->combine_regions ()) != 0) {
7774 new_selection.push_back (rv);
7778 selection->clear_regions ();
7779 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7780 selection->add (*i);
7783 commit_reversible_command ();
7787 Editor::uncombine_regions ()
7789 typedef set<RouteTimeAxisView*> RTVS;
7792 if (selection->regions.empty()) {
7796 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7797 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7800 tracks.insert (rtv);
7804 begin_reversible_command (_("uncombine regions"));
7806 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7807 (*i)->uncombine_regions ();
7810 commit_reversible_command ();
7814 Editor::toggle_midi_input_active (bool flip_others)
7817 boost::shared_ptr<RouteList> rl (new RouteList);
7819 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7820 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7826 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7829 rl->push_back (rtav->route());
7830 onoff = !mt->input_active();
7834 _session->set_exclusive_input_active (rl, onoff, flip_others);
7841 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7843 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7844 lock_dialog->get_vbox()->pack_start (*padlock);
7846 ArdourButton* b = manage (new ArdourButton);
7847 b->set_name ("lock button");
7848 b->set_text (_("Click to unlock"));
7849 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7850 lock_dialog->get_vbox()->pack_start (*b);
7852 lock_dialog->get_vbox()->show_all ();
7853 lock_dialog->set_size_request (200, 200);
7856 delete _main_menu_disabler;
7857 _main_menu_disabler = new MainMenuDisabler;
7859 lock_dialog->present ();
7865 lock_dialog->hide ();
7867 delete _main_menu_disabler;
7868 _main_menu_disabler = 0;
7870 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7871 start_lock_event_timing ();
7876 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7878 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7882 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7884 Timers::TimerSuspender t;
7885 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7886 Gtkmm2ext::UI::instance()->flush_pending ();
7890 Editor::bring_all_sources_into_session ()
7897 ArdourDialog w (_("Moving embedded files into session folder"));
7898 w.get_vbox()->pack_start (msg);
7901 /* flush all pending GUI events because we're about to start copying
7905 Timers::TimerSuspender t;
7906 Gtkmm2ext::UI::instance()->flush_pending ();
7910 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));