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);
1692 Editor::temporal_zoom_step (bool coarser)
1694 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1696 framecnt_t nspp = samples_per_pixel;
1704 temporal_zoom (nspp);
1708 Editor::temporal_zoom (framecnt_t fpp)
1714 framepos_t current_page = current_page_samples();
1715 framepos_t current_leftmost = leftmost_frame;
1716 framepos_t current_rightmost;
1717 framepos_t current_center;
1718 framepos_t new_page_size;
1719 framepos_t half_page_size;
1720 framepos_t leftmost_after_zoom = 0;
1722 bool in_track_canvas;
1726 if (fpp == samples_per_pixel) {
1730 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1731 // segfaults for lack of memory. If somebody decides this is not high enough I
1732 // believe it can be raisen to higher values but some limit must be in place.
1734 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1735 // all of which is used for the editor track displays. The whole day
1736 // would be 4147200000 samples, so 2592000 samples per pixel.
1738 nfpp = min (fpp, (framecnt_t) 2592000);
1739 nfpp = max ((framecnt_t) 1, nfpp);
1741 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1742 half_page_size = new_page_size / 2;
1744 switch (zoom_focus) {
1746 leftmost_after_zoom = current_leftmost;
1749 case ZoomFocusRight:
1750 current_rightmost = leftmost_frame + current_page;
1751 if (current_rightmost < new_page_size) {
1752 leftmost_after_zoom = 0;
1754 leftmost_after_zoom = current_rightmost - new_page_size;
1758 case ZoomFocusCenter:
1759 current_center = current_leftmost + (current_page/2);
1760 if (current_center < half_page_size) {
1761 leftmost_after_zoom = 0;
1763 leftmost_after_zoom = current_center - half_page_size;
1767 case ZoomFocusPlayhead:
1768 /* centre playhead */
1769 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1772 leftmost_after_zoom = 0;
1773 } else if (l > max_framepos) {
1774 leftmost_after_zoom = max_framepos - new_page_size;
1776 leftmost_after_zoom = (framepos_t) l;
1780 case ZoomFocusMouse:
1781 /* try to keep the mouse over the same point in the display */
1783 if (!mouse_frame (where, in_track_canvas)) {
1784 /* use playhead instead */
1785 where = playhead_cursor->current_frame ();
1787 if (where < half_page_size) {
1788 leftmost_after_zoom = 0;
1790 leftmost_after_zoom = where - half_page_size;
1795 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1798 leftmost_after_zoom = 0;
1799 } else if (l > max_framepos) {
1800 leftmost_after_zoom = max_framepos - new_page_size;
1802 leftmost_after_zoom = (framepos_t) l;
1809 /* try to keep the edit point in the same place */
1810 where = get_preferred_edit_position ();
1814 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1817 leftmost_after_zoom = 0;
1818 } else if (l > max_framepos) {
1819 leftmost_after_zoom = max_framepos - new_page_size;
1821 leftmost_after_zoom = (framepos_t) l;
1825 /* edit point not defined */
1832 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1834 reposition_and_zoom (leftmost_after_zoom, nfpp);
1838 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1840 /* this func helps make sure we leave a little space
1841 at each end of the editor so that the zoom doesn't fit the region
1842 precisely to the screen.
1845 GdkScreen* screen = gdk_screen_get_default ();
1846 const gint pixwidth = gdk_screen_get_width (screen);
1847 const gint mmwidth = gdk_screen_get_width_mm (screen);
1848 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1849 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1851 const framepos_t range = end - start;
1852 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1853 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1855 if (start > extra_samples) {
1856 start -= extra_samples;
1861 if (max_framepos - extra_samples > end) {
1862 end += extra_samples;
1869 Editor::temporal_zoom_region (bool both_axes)
1871 framepos_t start = max_framepos;
1873 set<TimeAxisView*> tracks;
1875 if ( !get_selection_extents(start, end) )
1878 calc_extra_zoom_edges (start, end);
1880 /* if we're zooming on both axes we need to save track heights etc.
1883 undo_visual_stack.push_back (current_visual_state (both_axes));
1885 PBD::Unwinder<bool> nsv (no_save_visual, true);
1887 temporal_zoom_by_frame (start, end);
1890 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1892 /* set visible track heights appropriately */
1894 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1895 (*t)->set_height (per_track_height);
1898 /* hide irrelevant tracks */
1900 DisplaySuspender ds;
1902 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1903 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1904 hide_track_in_display (*i);
1908 vertical_adjustment.set_value (0.0);
1911 redo_visual_stack.push_back (current_visual_state (both_axes));
1916 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1918 start = max_framepos;
1922 //ToDo: if notes are selected, set extents to that selection
1924 //ToDo: if control points are selected, set extents to that selection
1926 if ( !selection->regions.empty() ) {
1927 RegionSelection rs = get_regions_from_selection_and_entered ();
1929 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1931 if ((*i)->region()->position() < start) {
1932 start = (*i)->region()->position();
1935 if ((*i)->region()->last_frame() + 1 > end) {
1936 end = (*i)->region()->last_frame() + 1;
1940 } else if (!selection->time.empty()) {
1941 start = selection->time.start();
1942 end = selection->time.end_frame();
1944 ret = false; //no selection found
1947 if ((start == 0 && end == 0) || end < start) {
1956 Editor::temporal_zoom_selection (bool both_axes)
1958 if (!selection) return;
1960 //ToDo: if notes are selected, zoom to that
1962 //ToDo: if control points are selected, zoom to that
1964 //if region(s) are selected, zoom to that
1965 if ( !selection->regions.empty() )
1966 temporal_zoom_region (both_axes);
1968 //if a range is selected, zoom to that
1969 if (!selection->time.empty()) {
1971 framepos_t start, end;
1972 if (get_selection_extents (start, end)) {
1973 calc_extra_zoom_edges(start, end);
1974 temporal_zoom_by_frame (start, end);
1984 Editor::temporal_zoom_session ()
1986 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1989 framecnt_t start = _session->current_start_frame();
1990 framecnt_t end = _session->current_end_frame();
1992 if (_session->actively_recording () ) {
1993 framepos_t cur = playhead_cursor->current_frame ();
1995 /* recording beyond the end marker; zoom out
1996 * by 5 seconds more so that if 'follow
1997 * playhead' is active we don't immediately
2000 end = cur + _session->frame_rate() * 5;
2004 if ((start == 0 && end == 0) || end < start) {
2008 calc_extra_zoom_edges(start, end);
2010 temporal_zoom_by_frame (start, end);
2015 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2017 if (!_session) return;
2019 if ((start == 0 && end == 0) || end < start) {
2023 framepos_t range = end - start;
2025 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2027 framepos_t new_page = range;
2028 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2029 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2031 if (new_leftmost > middle) {
2035 if (new_leftmost < 0) {
2039 reposition_and_zoom (new_leftmost, new_fpp);
2043 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2049 framecnt_t range_before = frame - leftmost_frame;
2053 if (samples_per_pixel <= 1) {
2056 new_spp = samples_per_pixel + (samples_per_pixel/2);
2058 range_before += range_before/2;
2060 if (samples_per_pixel >= 1) {
2061 new_spp = samples_per_pixel - (samples_per_pixel/2);
2063 /* could bail out here since we cannot zoom any finer,
2064 but leave that to the equality test below
2066 new_spp = samples_per_pixel;
2069 range_before -= range_before/2;
2072 if (new_spp == samples_per_pixel) {
2076 /* zoom focus is automatically taken as @param frame when this
2080 framepos_t new_leftmost = frame - (framepos_t)range_before;
2082 if (new_leftmost > frame) {
2086 if (new_leftmost < 0) {
2090 reposition_and_zoom (new_leftmost, new_spp);
2095 Editor::choose_new_marker_name(string &name) {
2097 if (!UIConfiguration::instance().get_name_new_markers()) {
2098 /* don't prompt user for a new name */
2102 ArdourPrompter dialog (true);
2104 dialog.set_prompt (_("New Name:"));
2106 dialog.set_title (_("New Location Marker"));
2108 dialog.set_name ("MarkNameWindow");
2109 dialog.set_size_request (250, -1);
2110 dialog.set_position (Gtk::WIN_POS_MOUSE);
2112 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2113 dialog.set_initial_text (name);
2117 switch (dialog.run ()) {
2118 case RESPONSE_ACCEPT:
2124 dialog.get_result(name);
2131 Editor::add_location_from_selection ()
2135 if (selection->time.empty()) {
2139 if (_session == 0 || clicked_axisview == 0) {
2143 framepos_t start = selection->time[clicked_selection].start;
2144 framepos_t end = selection->time[clicked_selection].end;
2146 _session->locations()->next_available_name(rangename,"selection");
2147 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2149 begin_reversible_command (_("add marker"));
2151 XMLNode &before = _session->locations()->get_state();
2152 _session->locations()->add (location, true);
2153 XMLNode &after = _session->locations()->get_state();
2154 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2156 commit_reversible_command ();
2160 Editor::add_location_mark (framepos_t where)
2164 select_new_marker = true;
2166 _session->locations()->next_available_name(markername,"mark");
2167 if (!choose_new_marker_name(markername)) {
2170 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2171 begin_reversible_command (_("add marker"));
2173 XMLNode &before = _session->locations()->get_state();
2174 _session->locations()->add (location, true);
2175 XMLNode &after = _session->locations()->get_state();
2176 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2178 commit_reversible_command ();
2182 Editor::set_session_start_from_playhead ()
2188 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2189 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2191 XMLNode &before = loc->get_state();
2193 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2195 XMLNode &after = loc->get_state();
2197 begin_reversible_command (_("Set session start"));
2199 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2201 commit_reversible_command ();
2206 Editor::set_session_end_from_playhead ()
2212 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2213 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2215 XMLNode &before = loc->get_state();
2217 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2219 XMLNode &after = loc->get_state();
2221 begin_reversible_command (_("Set session start"));
2223 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2225 commit_reversible_command ();
2230 Editor::add_location_from_playhead_cursor ()
2232 add_location_mark (_session->audible_frame());
2236 Editor::remove_location_at_playhead_cursor ()
2240 XMLNode &before = _session->locations()->get_state();
2241 bool removed = false;
2243 //find location(s) at this time
2244 Locations::LocationList locs;
2245 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2246 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2247 if ((*i)->is_mark()) {
2248 _session->locations()->remove (*i);
2255 begin_reversible_command (_("remove marker"));
2256 XMLNode &after = _session->locations()->get_state();
2257 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2258 commit_reversible_command ();
2263 /** Add a range marker around each selected region */
2265 Editor::add_locations_from_region ()
2267 RegionSelection rs = get_regions_from_selection_and_entered ();
2272 bool commit = false;
2274 XMLNode &before = _session->locations()->get_state();
2276 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2278 boost::shared_ptr<Region> region = (*i)->region ();
2280 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2282 _session->locations()->add (location, true);
2287 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2288 XMLNode &after = _session->locations()->get_state();
2289 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2290 commit_reversible_command ();
2294 /** Add a single range marker around all selected regions */
2296 Editor::add_location_from_region ()
2298 RegionSelection rs = get_regions_from_selection_and_entered ();
2304 XMLNode &before = _session->locations()->get_state();
2308 if (rs.size() > 1) {
2309 _session->locations()->next_available_name(markername, "regions");
2311 RegionView* rv = *(rs.begin());
2312 boost::shared_ptr<Region> region = rv->region();
2313 markername = region->name();
2316 if (!choose_new_marker_name(markername)) {
2320 // single range spanning all selected
2321 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2322 _session->locations()->add (location, true);
2324 begin_reversible_command (_("add marker"));
2325 XMLNode &after = _session->locations()->get_state();
2326 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2327 commit_reversible_command ();
2333 Editor::jump_forward_to_mark ()
2339 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2345 _session->request_locate (pos, _session->transport_rolling());
2349 Editor::jump_backward_to_mark ()
2355 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2361 _session->request_locate (pos, _session->transport_rolling());
2367 framepos_t const pos = _session->audible_frame ();
2370 _session->locations()->next_available_name (markername, "mark");
2372 if (!choose_new_marker_name (markername)) {
2376 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2380 Editor::clear_markers ()
2383 begin_reversible_command (_("clear markers"));
2385 XMLNode &before = _session->locations()->get_state();
2386 _session->locations()->clear_markers ();
2387 XMLNode &after = _session->locations()->get_state();
2388 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2390 commit_reversible_command ();
2395 Editor::clear_ranges ()
2398 begin_reversible_command (_("clear ranges"));
2400 XMLNode &before = _session->locations()->get_state();
2402 _session->locations()->clear_ranges ();
2404 XMLNode &after = _session->locations()->get_state();
2405 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2407 commit_reversible_command ();
2412 Editor::clear_locations ()
2414 begin_reversible_command (_("clear locations"));
2416 XMLNode &before = _session->locations()->get_state();
2417 _session->locations()->clear ();
2418 XMLNode &after = _session->locations()->get_state();
2419 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2421 commit_reversible_command ();
2425 Editor::unhide_markers ()
2427 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2428 Location *l = (*i).first;
2429 if (l->is_hidden() && l->is_mark()) {
2430 l->set_hidden(false, this);
2436 Editor::unhide_ranges ()
2438 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2439 Location *l = (*i).first;
2440 if (l->is_hidden() && l->is_range_marker()) {
2441 l->set_hidden(false, this);
2446 /* INSERT/REPLACE */
2449 Editor::insert_region_list_selection (float times)
2451 RouteTimeAxisView *tv = 0;
2452 boost::shared_ptr<Playlist> playlist;
2454 if (clicked_routeview != 0) {
2455 tv = clicked_routeview;
2456 } else if (!selection->tracks.empty()) {
2457 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2460 } else if (entered_track != 0) {
2461 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2468 if ((playlist = tv->playlist()) == 0) {
2472 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2477 begin_reversible_command (_("insert region"));
2478 playlist->clear_changes ();
2479 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2480 if (Config->get_edit_mode() == Ripple)
2481 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2483 _session->add_command(new StatefulDiffCommand (playlist));
2484 commit_reversible_command ();
2487 /* BUILT-IN EFFECTS */
2490 Editor::reverse_selection ()
2495 /* GAIN ENVELOPE EDITING */
2498 Editor::edit_envelope ()
2505 Editor::transition_to_rolling (bool fwd)
2511 if (_session->config.get_external_sync()) {
2512 switch (Config->get_sync_source()) {
2516 /* transport controlled by the master */
2521 if (_session->is_auditioning()) {
2522 _session->cancel_audition ();
2526 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2530 Editor::play_from_start ()
2532 _session->request_locate (_session->current_start_frame(), true);
2536 Editor::play_from_edit_point ()
2538 _session->request_locate (get_preferred_edit_position(), true);
2542 Editor::play_from_edit_point_and_return ()
2544 framepos_t start_frame;
2545 framepos_t return_frame;
2547 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2549 if (_session->transport_rolling()) {
2550 _session->request_locate (start_frame, false);
2554 /* don't reset the return frame if its already set */
2556 if ((return_frame = _session->requested_return_frame()) < 0) {
2557 return_frame = _session->audible_frame();
2560 if (start_frame >= 0) {
2561 _session->request_roll_at_and_return (start_frame, return_frame);
2566 Editor::play_selection ()
2568 framepos_t start, end;
2569 if (!get_selection_extents ( start, end))
2572 AudioRange ar (start, end, 0);
2573 list<AudioRange> lar;
2576 _session->request_play_range (&lar, true);
2580 Editor::get_preroll ()
2582 return Config->get_preroll_seconds() * _session->frame_rate();
2587 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2589 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2592 location -= get_preroll();
2594 //don't try to locate before the beginning of time
2598 //if follow_playhead is on, keep the playhead on the screen
2599 if ( _follow_playhead )
2600 if ( location < leftmost_frame )
2601 location = leftmost_frame;
2603 _session->request_locate( location );
2607 Editor::play_with_preroll ()
2610 framepos_t preroll = get_preroll();
2612 framepos_t start, end;
2613 if (!get_selection_extents ( start, end))
2616 if (start > preroll)
2617 start = start - preroll;
2619 end = end + preroll; //"post-roll"
2621 AudioRange ar (start, end, 0);
2622 list<AudioRange> lar;
2625 _session->request_play_range (&lar, true);
2630 Editor::play_location (Location& location)
2632 if (location.start() <= location.end()) {
2636 _session->request_bounded_roll (location.start(), location.end());
2640 Editor::loop_location (Location& location)
2642 if (location.start() <= location.end()) {
2648 if ((tll = transport_loop_location()) != 0) {
2649 tll->set (location.start(), location.end());
2651 // enable looping, reposition and start rolling
2652 _session->request_locate (tll->start(), true);
2653 _session->request_play_loop (true);
2658 Editor::do_layer_operation (LayerOperation op)
2660 if (selection->regions.empty ()) {
2664 bool const multiple = selection->regions.size() > 1;
2668 begin_reversible_command (_("raise regions"));
2670 begin_reversible_command (_("raise region"));
2676 begin_reversible_command (_("raise regions to top"));
2678 begin_reversible_command (_("raise region to top"));
2684 begin_reversible_command (_("lower regions"));
2686 begin_reversible_command (_("lower region"));
2692 begin_reversible_command (_("lower regions to bottom"));
2694 begin_reversible_command (_("lower region"));
2699 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2700 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2701 (*i)->clear_owned_changes ();
2704 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2705 boost::shared_ptr<Region> r = (*i)->region ();
2717 r->lower_to_bottom ();
2721 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2722 vector<Command*> cmds;
2724 _session->add_commands (cmds);
2727 commit_reversible_command ();
2731 Editor::raise_region ()
2733 do_layer_operation (Raise);
2737 Editor::raise_region_to_top ()
2739 do_layer_operation (RaiseToTop);
2743 Editor::lower_region ()
2745 do_layer_operation (Lower);
2749 Editor::lower_region_to_bottom ()
2751 do_layer_operation (LowerToBottom);
2754 /** Show the region editor for the selected regions */
2756 Editor::show_region_properties ()
2758 selection->foreach_regionview (&RegionView::show_region_editor);
2761 /** Show the midi list editor for the selected MIDI regions */
2763 Editor::show_midi_list_editor ()
2765 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2769 Editor::rename_region ()
2771 RegionSelection rs = get_regions_from_selection_and_entered ();
2777 ArdourDialog d (*this, _("Rename Region"), true, false);
2779 Label label (_("New name:"));
2782 hbox.set_spacing (6);
2783 hbox.pack_start (label, false, false);
2784 hbox.pack_start (entry, true, true);
2786 d.get_vbox()->set_border_width (12);
2787 d.get_vbox()->pack_start (hbox, false, false);
2789 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2790 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2792 d.set_size_request (300, -1);
2794 entry.set_text (rs.front()->region()->name());
2795 entry.select_region (0, -1);
2797 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2803 int const ret = d.run();
2807 if (ret != RESPONSE_OK) {
2811 std::string str = entry.get_text();
2812 strip_whitespace_edges (str);
2814 rs.front()->region()->set_name (str);
2815 _regions->redisplay ();
2819 /** Start an audition of the first selected region */
2821 Editor::play_edit_range ()
2823 framepos_t start, end;
2825 if (get_edit_op_range (start, end)) {
2826 _session->request_bounded_roll (start, end);
2831 Editor::play_selected_region ()
2833 framepos_t start = max_framepos;
2836 RegionSelection rs = get_regions_from_selection_and_entered ();
2842 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2843 if ((*i)->region()->position() < start) {
2844 start = (*i)->region()->position();
2846 if ((*i)->region()->last_frame() + 1 > end) {
2847 end = (*i)->region()->last_frame() + 1;
2851 _session->request_bounded_roll (start, end);
2855 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2857 _session->audition_region (region);
2861 Editor::region_from_selection ()
2863 if (clicked_axisview == 0) {
2867 if (selection->time.empty()) {
2871 framepos_t start = selection->time[clicked_selection].start;
2872 framepos_t end = selection->time[clicked_selection].end;
2874 TrackViewList tracks = get_tracks_for_range_action ();
2876 framepos_t selection_cnt = end - start + 1;
2878 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2879 boost::shared_ptr<Region> current;
2880 boost::shared_ptr<Playlist> pl;
2881 framepos_t internal_start;
2884 if ((pl = (*i)->playlist()) == 0) {
2888 if ((current = pl->top_region_at (start)) == 0) {
2892 internal_start = start - current->position();
2893 RegionFactory::region_name (new_name, current->name(), true);
2897 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2898 plist.add (ARDOUR::Properties::length, selection_cnt);
2899 plist.add (ARDOUR::Properties::name, new_name);
2900 plist.add (ARDOUR::Properties::layer, 0);
2902 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2907 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2909 if (selection->time.empty() || selection->tracks.empty()) {
2913 framepos_t start, end;
2914 if (clicked_selection) {
2915 start = selection->time[clicked_selection].start;
2916 end = selection->time[clicked_selection].end;
2918 start = selection->time.start();
2919 end = selection->time.end_frame();
2922 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2923 sort_track_selection (ts);
2925 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2926 boost::shared_ptr<Region> current;
2927 boost::shared_ptr<Playlist> playlist;
2928 framepos_t internal_start;
2931 if ((playlist = (*i)->playlist()) == 0) {
2935 if ((current = playlist->top_region_at(start)) == 0) {
2939 internal_start = start - current->position();
2940 RegionFactory::region_name (new_name, current->name(), true);
2944 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2945 plist.add (ARDOUR::Properties::length, end - start + 1);
2946 plist.add (ARDOUR::Properties::name, new_name);
2948 new_regions.push_back (RegionFactory::create (current, plist));
2953 Editor::split_multichannel_region ()
2955 RegionSelection rs = get_regions_from_selection_and_entered ();
2961 vector< boost::shared_ptr<Region> > v;
2963 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2964 (*x)->region()->separate_by_channel (*_session, v);
2969 Editor::new_region_from_selection ()
2971 region_from_selection ();
2972 cancel_selection ();
2976 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2978 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2979 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2980 case Evoral::OverlapNone:
2988 * - selected tracks, or if there are none...
2989 * - tracks containing selected regions, or if there are none...
2994 Editor::get_tracks_for_range_action () const
2998 if (selection->tracks.empty()) {
3000 /* use tracks with selected regions */
3002 RegionSelection rs = selection->regions;
3004 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3005 TimeAxisView* tv = &(*i)->get_time_axis_view();
3007 if (!t.contains (tv)) {
3013 /* no regions and no tracks: use all tracks */
3019 t = selection->tracks;
3022 return t.filter_to_unique_playlists();
3026 Editor::separate_regions_between (const TimeSelection& ts)
3028 bool in_command = false;
3029 boost::shared_ptr<Playlist> playlist;
3030 RegionSelection new_selection;
3032 TrackViewList tmptracks = get_tracks_for_range_action ();
3033 sort_track_selection (tmptracks);
3035 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3037 RouteTimeAxisView* rtv;
3039 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3041 if (rtv->is_track()) {
3043 /* no edits to destructive tracks */
3045 if (rtv->track()->destructive()) {
3049 if ((playlist = rtv->playlist()) != 0) {
3051 playlist->clear_changes ();
3053 /* XXX need to consider musical time selections here at some point */
3055 double speed = rtv->track()->speed();
3058 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3060 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3061 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3063 latest_regionviews.clear ();
3065 playlist->partition ((framepos_t)((*t).start * speed),
3066 (framepos_t)((*t).end * speed), false);
3070 if (!latest_regionviews.empty()) {
3072 rtv->view()->foreach_regionview (sigc::bind (
3073 sigc::ptr_fun (add_if_covered),
3074 &(*t), &new_selection));
3077 begin_reversible_command (_("separate"));
3081 /* pick up changes to existing regions */
3083 vector<Command*> cmds;
3084 playlist->rdiff (cmds);
3085 _session->add_commands (cmds);
3087 /* pick up changes to the playlist itself (adds/removes)
3090 _session->add_command(new StatefulDiffCommand (playlist));
3099 // selection->set (new_selection);
3101 commit_reversible_command ();
3105 struct PlaylistState {
3106 boost::shared_ptr<Playlist> playlist;
3110 /** Take tracks from get_tracks_for_range_action and cut any regions
3111 * on those tracks so that the tracks are empty over the time
3115 Editor::separate_region_from_selection ()
3117 /* preferentially use *all* ranges in the time selection if we're in range mode
3118 to allow discontiguous operation, since get_edit_op_range() currently
3119 returns a single range.
3122 if (!selection->time.empty()) {
3124 separate_regions_between (selection->time);
3131 if (get_edit_op_range (start, end)) {
3133 AudioRange ar (start, end, 1);
3137 separate_regions_between (ts);
3143 Editor::separate_region_from_punch ()
3145 Location* loc = _session->locations()->auto_punch_location();
3147 separate_regions_using_location (*loc);
3152 Editor::separate_region_from_loop ()
3154 Location* loc = _session->locations()->auto_loop_location();
3156 separate_regions_using_location (*loc);
3161 Editor::separate_regions_using_location (Location& loc)
3163 if (loc.is_mark()) {
3167 AudioRange ar (loc.start(), loc.end(), 1);
3172 separate_regions_between (ts);
3175 /** Separate regions under the selected region */
3177 Editor::separate_under_selected_regions ()
3179 vector<PlaylistState> playlists;
3183 rs = get_regions_from_selection_and_entered();
3185 if (!_session || rs.empty()) {
3189 begin_reversible_command (_("separate region under"));
3191 list<boost::shared_ptr<Region> > regions_to_remove;
3193 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3194 // we can't just remove the region(s) in this loop because
3195 // this removes them from the RegionSelection, and they thus
3196 // disappear from underneath the iterator, and the ++i above
3197 // SEGVs in a puzzling fashion.
3199 // so, first iterate over the regions to be removed from rs and
3200 // add them to the regions_to_remove list, and then
3201 // iterate over the list to actually remove them.
3203 regions_to_remove.push_back ((*i)->region());
3206 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3208 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3211 // is this check necessary?
3215 vector<PlaylistState>::iterator i;
3217 //only take state if this is a new playlist.
3218 for (i = playlists.begin(); i != playlists.end(); ++i) {
3219 if ((*i).playlist == playlist) {
3224 if (i == playlists.end()) {
3226 PlaylistState before;
3227 before.playlist = playlist;
3228 before.before = &playlist->get_state();
3230 playlist->freeze ();
3231 playlists.push_back(before);
3234 //Partition on the region bounds
3235 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3237 //Re-add region that was just removed due to the partition operation
3238 playlist->add_region( (*rl), (*rl)->first_frame() );
3241 vector<PlaylistState>::iterator pl;
3243 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3244 (*pl).playlist->thaw ();
3245 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3248 commit_reversible_command ();
3252 Editor::crop_region_to_selection ()
3254 if (!selection->time.empty()) {
3256 crop_region_to (selection->time.start(), selection->time.end_frame());
3263 if (get_edit_op_range (start, end)) {
3264 crop_region_to (start, end);
3271 Editor::crop_region_to (framepos_t start, framepos_t end)
3273 vector<boost::shared_ptr<Playlist> > playlists;
3274 boost::shared_ptr<Playlist> playlist;
3277 if (selection->tracks.empty()) {
3278 ts = track_views.filter_to_unique_playlists();
3280 ts = selection->tracks.filter_to_unique_playlists ();
3283 sort_track_selection (ts);
3285 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3287 RouteTimeAxisView* rtv;
3289 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3291 boost::shared_ptr<Track> t = rtv->track();
3293 if (t != 0 && ! t->destructive()) {
3295 if ((playlist = rtv->playlist()) != 0) {
3296 playlists.push_back (playlist);
3302 if (playlists.empty()) {
3307 framepos_t new_start;
3309 framecnt_t new_length;
3310 bool in_command = false;
3312 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3314 /* Only the top regions at start and end have to be cropped */
3315 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3316 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3318 vector<boost::shared_ptr<Region> > regions;
3320 if (region_at_start != 0) {
3321 regions.push_back (region_at_start);
3323 if (region_at_end != 0) {
3324 regions.push_back (region_at_end);
3327 /* now adjust lengths */
3328 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3330 pos = (*i)->position();
3331 new_start = max (start, pos);
3332 if (max_framepos - pos > (*i)->length()) {
3333 new_end = pos + (*i)->length() - 1;
3335 new_end = max_framepos;
3337 new_end = min (end, new_end);
3338 new_length = new_end - new_start + 1;
3341 begin_reversible_command (_("trim to selection"));
3344 (*i)->clear_changes ();
3345 (*i)->trim_to (new_start, new_length);
3346 _session->add_command (new StatefulDiffCommand (*i));
3351 commit_reversible_command ();
3356 Editor::region_fill_track ()
3358 boost::shared_ptr<Playlist> playlist;
3359 RegionSelection regions = get_regions_from_selection_and_entered ();
3360 RegionSelection foo;
3362 framepos_t const end = _session->current_end_frame ();
3364 if (regions.empty () || regions.end_frame () + 1 >= end) {
3368 framepos_t const start_frame = regions.start ();
3369 framepos_t const end_frame = regions.end_frame ();
3370 framecnt_t const gap = end_frame - start_frame + 1;
3372 begin_reversible_command (Operations::region_fill);
3374 selection->clear_regions ();
3376 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3378 boost::shared_ptr<Region> r ((*i)->region());
3380 TimeAxisView& tv = (*i)->get_time_axis_view();
3381 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3382 latest_regionviews.clear ();
3383 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3385 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3386 playlist = (*i)->region()->playlist();
3387 playlist->clear_changes ();
3388 playlist->duplicate_until (r, position, gap, end);
3389 _session->add_command(new StatefulDiffCommand (playlist));
3393 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3397 selection->set (foo);
3400 commit_reversible_command ();
3404 Editor::set_region_sync_position ()
3406 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3410 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3412 bool in_command = false;
3414 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3416 if (!(*r)->region()->covers (where)) {
3420 boost::shared_ptr<Region> region ((*r)->region());
3423 begin_reversible_command (_("set sync point"));
3427 region->clear_changes ();
3428 region->set_sync_position (where);
3429 _session->add_command(new StatefulDiffCommand (region));
3433 commit_reversible_command ();
3437 /** Remove the sync positions of the selection */
3439 Editor::remove_region_sync ()
3441 RegionSelection rs = get_regions_from_selection_and_entered ();
3447 begin_reversible_command (_("remove region sync"));
3449 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3451 (*i)->region()->clear_changes ();
3452 (*i)->region()->clear_sync_position ();
3453 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3456 commit_reversible_command ();
3460 Editor::naturalize_region ()
3462 RegionSelection rs = get_regions_from_selection_and_entered ();
3468 if (rs.size() > 1) {
3469 begin_reversible_command (_("move regions to original position"));
3471 begin_reversible_command (_("move region to original position"));
3474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3475 (*i)->region()->clear_changes ();
3476 (*i)->region()->move_to_natural_position ();
3477 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3480 commit_reversible_command ();
3484 Editor::align_regions (RegionPoint what)
3486 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3492 begin_reversible_command (_("align selection"));
3494 framepos_t const position = get_preferred_edit_position ();
3496 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3497 align_region_internal ((*i)->region(), what, position);
3500 commit_reversible_command ();
3503 struct RegionSortByTime {
3504 bool operator() (const RegionView* a, const RegionView* b) {
3505 return a->region()->position() < b->region()->position();
3510 Editor::align_regions_relative (RegionPoint point)
3512 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3518 framepos_t const position = get_preferred_edit_position ();
3520 framepos_t distance = 0;
3524 list<RegionView*> sorted;
3525 rs.by_position (sorted);
3527 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3532 if (position > r->position()) {
3533 distance = position - r->position();
3535 distance = r->position() - position;
3541 if (position > r->last_frame()) {
3542 distance = position - r->last_frame();
3543 pos = r->position() + distance;
3545 distance = r->last_frame() - position;
3546 pos = r->position() - distance;
3552 pos = r->adjust_to_sync (position);
3553 if (pos > r->position()) {
3554 distance = pos - r->position();
3556 distance = r->position() - pos;
3562 if (pos == r->position()) {
3566 begin_reversible_command (_("align selection (relative)"));
3568 /* move first one specially */
3570 r->clear_changes ();
3571 r->set_position (pos);
3572 _session->add_command(new StatefulDiffCommand (r));
3574 /* move rest by the same amount */
3578 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3580 boost::shared_ptr<Region> region ((*i)->region());
3582 region->clear_changes ();
3585 region->set_position (region->position() + distance);
3587 region->set_position (region->position() - distance);
3590 _session->add_command(new StatefulDiffCommand (region));
3594 commit_reversible_command ();
3598 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3600 begin_reversible_command (_("align region"));
3601 align_region_internal (region, point, position);
3602 commit_reversible_command ();
3606 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3608 region->clear_changes ();
3612 region->set_position (region->adjust_to_sync (position));
3616 if (position > region->length()) {
3617 region->set_position (position - region->length());
3622 region->set_position (position);
3626 _session->add_command(new StatefulDiffCommand (region));
3630 Editor::trim_region_front ()
3636 Editor::trim_region_back ()
3638 trim_region (false);
3642 Editor::trim_region (bool front)
3644 framepos_t where = get_preferred_edit_position();
3645 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3651 begin_reversible_command (front ? _("trim front") : _("trim back"));
3653 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3654 if (!(*i)->region()->locked()) {
3656 (*i)->region()->clear_changes ();
3659 (*i)->region()->trim_front (where);
3660 maybe_locate_with_edit_preroll ( where );
3662 (*i)->region()->trim_end (where);
3663 maybe_locate_with_edit_preroll ( where );
3666 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3670 commit_reversible_command ();
3673 /** Trim the end of the selected regions to the position of the edit cursor */
3675 Editor::trim_region_to_loop ()
3677 Location* loc = _session->locations()->auto_loop_location();
3681 trim_region_to_location (*loc, _("trim to loop"));
3685 Editor::trim_region_to_punch ()
3687 Location* loc = _session->locations()->auto_punch_location();
3691 trim_region_to_location (*loc, _("trim to punch"));
3695 Editor::trim_region_to_location (const Location& loc, const char* str)
3697 RegionSelection rs = get_regions_from_selection_and_entered ();
3698 bool in_command = false;
3700 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3701 RegionView* rv = (*x);
3703 /* require region to span proposed trim */
3704 switch (rv->region()->coverage (loc.start(), loc.end())) {
3705 case Evoral::OverlapInternal:
3711 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3720 if (tav->track() != 0) {
3721 speed = tav->track()->speed();
3724 start = session_frame_to_track_frame (loc.start(), speed);
3725 end = session_frame_to_track_frame (loc.end(), speed);
3727 rv->region()->clear_changes ();
3728 rv->region()->trim_to (start, (end - start));
3731 begin_reversible_command (str);
3734 _session->add_command(new StatefulDiffCommand (rv->region()));
3738 commit_reversible_command ();
3743 Editor::trim_region_to_previous_region_end ()
3745 return trim_to_region(false);
3749 Editor::trim_region_to_next_region_start ()
3751 return trim_to_region(true);
3755 Editor::trim_to_region(bool forward)
3757 RegionSelection rs = get_regions_from_selection_and_entered ();
3758 bool in_command = false;
3760 boost::shared_ptr<Region> next_region;
3762 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3764 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3770 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3778 if (atav->track() != 0) {
3779 speed = atav->track()->speed();
3783 boost::shared_ptr<Region> region = arv->region();
3784 boost::shared_ptr<Playlist> playlist (region->playlist());
3786 region->clear_changes ();
3790 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3796 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3797 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3801 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3807 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3809 arv->region_changed (ARDOUR::bounds_change);
3813 begin_reversible_command (_("trim to region"));
3816 _session->add_command(new StatefulDiffCommand (region));
3820 commit_reversible_command ();
3825 Editor::unfreeze_route ()
3827 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3831 clicked_routeview->track()->unfreeze ();
3835 Editor::_freeze_thread (void* arg)
3837 return static_cast<Editor*>(arg)->freeze_thread ();
3841 Editor::freeze_thread ()
3843 /* create event pool because we may need to talk to the session */
3844 SessionEvent::create_per_thread_pool ("freeze events", 64);
3845 /* create per-thread buffers for process() tree to use */
3846 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3847 current_interthread_info->done = true;
3852 Editor::freeze_route ()
3858 /* stop transport before we start. this is important */
3860 _session->request_transport_speed (0.0);
3862 /* wait for just a little while, because the above call is asynchronous */
3864 Glib::usleep (250000);
3866 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3870 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3872 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3873 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3875 d.set_title (_("Cannot freeze"));
3880 if (clicked_routeview->track()->has_external_redirects()) {
3881 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"
3882 "Freezing will only process the signal as far as the first send/insert/return."),
3883 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3885 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3886 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3887 d.set_title (_("Freeze Limits"));
3889 int response = d.run ();
3892 case Gtk::RESPONSE_CANCEL:
3899 InterThreadInfo itt;
3900 current_interthread_info = &itt;
3902 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3904 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3906 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3908 while (!itt.done && !itt.cancel) {
3909 gtk_main_iteration ();
3912 current_interthread_info = 0;
3916 Editor::bounce_range_selection (bool replace, bool enable_processing)
3918 if (selection->time.empty()) {
3922 TrackSelection views = selection->tracks;
3924 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3926 if (enable_processing) {
3928 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3930 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3932 _("You can't perform this operation because the processing of the signal "
3933 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3934 "You can do this without processing, which is a different operation.")
3936 d.set_title (_("Cannot bounce"));
3943 framepos_t start = selection->time[clicked_selection].start;
3944 framepos_t end = selection->time[clicked_selection].end;
3945 framepos_t cnt = end - start + 1;
3946 bool in_command = false;
3948 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3950 RouteTimeAxisView* rtv;
3952 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3956 boost::shared_ptr<Playlist> playlist;
3958 if ((playlist = rtv->playlist()) == 0) {
3962 InterThreadInfo itt;
3964 playlist->clear_changes ();
3965 playlist->clear_owned_changes ();
3967 boost::shared_ptr<Region> r;
3969 if (enable_processing) {
3970 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3972 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3980 list<AudioRange> ranges;
3981 ranges.push_back (AudioRange (start, start+cnt, 0));
3982 playlist->cut (ranges); // discard result
3983 playlist->add_region (r, start);
3987 begin_reversible_command (_("bounce range"));
3990 vector<Command*> cmds;
3991 playlist->rdiff (cmds);
3992 _session->add_commands (cmds);
3994 _session->add_command (new StatefulDiffCommand (playlist));
3998 commit_reversible_command ();
4002 /** Delete selected regions, automation points or a time range */
4006 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4007 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4008 bool deleted = false;
4009 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4010 deleted = current_mixer_strip->delete_processors ();
4016 /** Cut selected regions, automation points or a time range */
4023 /** Copy selected regions, automation points or a time range */
4031 /** @return true if a Cut, Copy or Clear is possible */
4033 Editor::can_cut_copy () const
4035 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4042 /** Cut, copy or clear selected regions, automation points or a time range.
4043 * @param op Operation (Delete, Cut, Copy or Clear)
4046 Editor::cut_copy (CutCopyOp op)
4048 /* only cancel selection if cut/copy is successful.*/
4054 opname = _("delete");
4063 opname = _("clear");
4067 /* if we're deleting something, and the mouse is still pressed,
4068 the thing we started a drag for will be gone when we release
4069 the mouse button(s). avoid this. see part 2 at the end of
4073 if (op == Delete || op == Cut || op == Clear) {
4074 if (_drags->active ()) {
4079 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4080 cut_buffer->clear ();
4082 if (entered_marker) {
4084 /* cut/delete op while pointing at a marker */
4087 Location* loc = find_location_from_marker (entered_marker, ignored);
4089 if (_session && loc) {
4090 entered_marker = NULL;
4091 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4098 switch (mouse_mode) {
4101 begin_reversible_command (opname + ' ' + X_("MIDI"));
4103 commit_reversible_command ();
4109 bool did_edit = false;
4111 if (!selection->regions.empty() || !selection->points.empty()) {
4112 begin_reversible_command (opname + ' ' + _("objects"));
4115 if (!selection->regions.empty()) {
4116 cut_copy_regions (op, selection->regions);
4118 if (op == Cut || op == Delete) {
4119 selection->clear_regions ();
4123 if (!selection->points.empty()) {
4124 cut_copy_points (op);
4126 if (op == Cut || op == Delete) {
4127 selection->clear_points ();
4130 } else if (selection->time.empty()) {
4131 framepos_t start, end;
4132 /* no time selection, see if we can get an edit range
4135 if (get_edit_op_range (start, end)) {
4136 selection->set (start, end);
4138 } else if (!selection->time.empty()) {
4139 begin_reversible_command (opname + ' ' + _("range"));
4142 cut_copy_ranges (op);
4144 if (op == Cut || op == Delete) {
4145 selection->clear_time ();
4150 /* reset repeated paste state */
4153 commit_reversible_command ();
4156 if (op == Delete || op == Cut || op == Clear) {
4161 struct AutomationRecord {
4162 AutomationRecord () : state (0) , line(NULL) {}
4163 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4165 XMLNode* state; ///< state before any operation
4166 const AutomationLine* line; ///< line this came from
4167 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4170 /** Cut, copy or clear selected automation points.
4171 * @param op Operation (Cut, Copy or Clear)
4174 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4176 if (selection->points.empty ()) {
4180 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4181 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4183 /* Keep a record of the AutomationLists that we end up using in this operation */
4184 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4187 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4188 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4189 const AutomationLine& line = (*i)->line();
4190 const boost::shared_ptr<AutomationList> al = line.the_list();
4191 if (lists.find (al) == lists.end ()) {
4192 /* We haven't seen this list yet, so make a record for it. This includes
4193 taking a copy of its current state, in case this is needed for undo later.
4195 lists[al] = AutomationRecord (&al->get_state (), &line);
4199 if (op == Cut || op == Copy) {
4200 /* This operation will involve putting things in the cut buffer, so create an empty
4201 ControlList for each of our source lists to put the cut buffer data in.
4203 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4204 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4207 /* Add all selected points to the relevant copy ControlLists */
4208 framepos_t start = std::numeric_limits<framepos_t>::max();
4209 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4210 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4211 AutomationList::const_iterator j = (*i)->model();
4213 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4215 /* Update earliest MIDI start time in beats */
4216 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4218 /* Update earliest session start time in frames */
4219 start = std::min(start, (*i)->line().session_position(j));
4223 /* Snap start time backwards, so copy/paste is snap aligned. */
4225 if (earliest == Evoral::Beats::max()) {
4226 earliest = Evoral::Beats(); // Weird... don't offset
4228 earliest.round_down_to_beat();
4230 if (start == std::numeric_limits<double>::max()) {
4231 start = 0; // Weird... don't offset
4233 snap_to(start, RoundDownMaybe);
4236 const double line_offset = midi ? earliest.to_double() : start;
4237 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4238 /* Correct this copy list so that it is relative to the earliest
4239 start time, so relative ordering between points is preserved
4240 when copying from several lists and the paste starts at the
4241 earliest copied piece of data. */
4242 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4243 (*j)->when -= line_offset;
4246 /* And add it to the cut buffer */
4247 cut_buffer->add (i->second.copy);
4251 if (op == Delete || op == Cut) {
4252 /* This operation needs to remove things from the main AutomationList, so do that now */
4254 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4255 i->first->freeze ();
4258 /* Remove each selected point from its AutomationList */
4259 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4260 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4261 al->erase ((*i)->model ());
4264 /* Thaw the lists and add undo records for them */
4265 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4266 boost::shared_ptr<AutomationList> al = i->first;
4268 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4273 /** Cut, copy or clear selected automation points.
4274 * @param op Operation (Cut, Copy or Clear)
4277 Editor::cut_copy_midi (CutCopyOp op)
4279 Evoral::Beats earliest = Evoral::Beats::max();
4280 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4281 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4283 if (!mrv->selection().empty()) {
4284 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4286 mrv->cut_copy_clear (op);
4288 /* XXX: not ideal, as there may be more than one track involved in the selection */
4289 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4293 if (!selection->points.empty()) {
4294 cut_copy_points (op, earliest, true);
4295 if (op == Cut || op == Delete) {
4296 selection->clear_points ();
4301 struct lt_playlist {
4302 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4303 return a.playlist < b.playlist;
4307 struct PlaylistMapping {
4309 boost::shared_ptr<Playlist> pl;
4311 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4314 /** Remove `clicked_regionview' */
4316 Editor::remove_clicked_region ()
4318 if (clicked_routeview == 0 || clicked_regionview == 0) {
4322 begin_reversible_command (_("remove region"));
4324 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4326 playlist->clear_changes ();
4327 playlist->clear_owned_changes ();
4328 playlist->remove_region (clicked_regionview->region());
4329 if (Config->get_edit_mode() == Ripple)
4330 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4332 /* We might have removed regions, which alters other regions' layering_index,
4333 so we need to do a recursive diff here.
4335 vector<Command*> cmds;
4336 playlist->rdiff (cmds);
4337 _session->add_commands (cmds);
4339 _session->add_command(new StatefulDiffCommand (playlist));
4340 commit_reversible_command ();
4344 /** Remove the selected regions */
4346 Editor::remove_selected_regions ()
4348 RegionSelection rs = get_regions_from_selection_and_entered ();
4350 if (!_session || rs.empty()) {
4354 list<boost::shared_ptr<Region> > regions_to_remove;
4356 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4357 // we can't just remove the region(s) in this loop because
4358 // this removes them from the RegionSelection, and they thus
4359 // disappear from underneath the iterator, and the ++i above
4360 // SEGVs in a puzzling fashion.
4362 // so, first iterate over the regions to be removed from rs and
4363 // add them to the regions_to_remove list, and then
4364 // iterate over the list to actually remove them.
4366 regions_to_remove.push_back ((*i)->region());
4369 vector<boost::shared_ptr<Playlist> > playlists;
4371 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4373 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4376 // is this check necessary?
4380 /* get_regions_from_selection_and_entered() guarantees that
4381 the playlists involved are unique, so there is no need
4385 playlists.push_back (playlist);
4387 playlist->clear_changes ();
4388 playlist->clear_owned_changes ();
4389 playlist->freeze ();
4390 playlist->remove_region (*rl);
4391 if (Config->get_edit_mode() == Ripple)
4392 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4396 vector<boost::shared_ptr<Playlist> >::iterator pl;
4397 bool in_command = false;
4399 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4402 /* We might have removed regions, which alters other regions' layering_index,
4403 so we need to do a recursive diff here.
4407 begin_reversible_command (_("remove region"));
4410 vector<Command*> cmds;
4411 (*pl)->rdiff (cmds);
4412 _session->add_commands (cmds);
4414 _session->add_command(new StatefulDiffCommand (*pl));
4418 commit_reversible_command ();
4422 /** Cut, copy or clear selected regions.
4423 * @param op Operation (Cut, Copy or Clear)
4426 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4428 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4429 a map when we want ordered access to both elements. i think.
4432 vector<PlaylistMapping> pmap;
4434 framepos_t first_position = max_framepos;
4436 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4437 FreezeList freezelist;
4439 /* get ordering correct before we cut/copy */
4441 rs.sort_by_position_and_track ();
4443 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4445 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4447 if (op == Cut || op == Clear || op == Delete) {
4448 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4451 FreezeList::iterator fl;
4453 // only take state if this is a new playlist.
4454 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4460 if (fl == freezelist.end()) {
4461 pl->clear_changes();
4462 pl->clear_owned_changes ();
4464 freezelist.insert (pl);
4469 TimeAxisView* tv = &(*x)->get_time_axis_view();
4470 vector<PlaylistMapping>::iterator z;
4472 for (z = pmap.begin(); z != pmap.end(); ++z) {
4473 if ((*z).tv == tv) {
4478 if (z == pmap.end()) {
4479 pmap.push_back (PlaylistMapping (tv));
4483 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4485 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4488 /* region not yet associated with a playlist (e.g. unfinished
4495 TimeAxisView& tv = (*x)->get_time_axis_view();
4496 boost::shared_ptr<Playlist> npl;
4497 RegionSelection::iterator tmp;
4504 vector<PlaylistMapping>::iterator z;
4506 for (z = pmap.begin(); z != pmap.end(); ++z) {
4507 if ((*z).tv == &tv) {
4512 assert (z != pmap.end());
4515 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4523 boost::shared_ptr<Region> r = (*x)->region();
4524 boost::shared_ptr<Region> _xx;
4530 pl->remove_region (r);
4531 if (Config->get_edit_mode() == Ripple)
4532 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4536 _xx = RegionFactory::create (r);
4537 npl->add_region (_xx, r->position() - first_position);
4538 pl->remove_region (r);
4539 if (Config->get_edit_mode() == Ripple)
4540 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4544 /* copy region before adding, so we're not putting same object into two different playlists */
4545 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4549 pl->remove_region (r);
4550 if (Config->get_edit_mode() == Ripple)
4551 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4560 list<boost::shared_ptr<Playlist> > foo;
4562 /* the pmap is in the same order as the tracks in which selected regions occured */
4564 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4567 foo.push_back ((*i).pl);
4572 cut_buffer->set (foo);
4576 _last_cut_copy_source_track = 0;
4578 _last_cut_copy_source_track = pmap.front().tv;
4582 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4585 /* We might have removed regions, which alters other regions' layering_index,
4586 so we need to do a recursive diff here.
4588 vector<Command*> cmds;
4589 (*pl)->rdiff (cmds);
4590 _session->add_commands (cmds);
4592 _session->add_command (new StatefulDiffCommand (*pl));
4597 Editor::cut_copy_ranges (CutCopyOp op)
4599 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4601 /* Sort the track selection now, so that it if is used, the playlists
4602 selected by the calls below to cut_copy_clear are in the order that
4603 their tracks appear in the editor. This makes things like paste
4604 of ranges work properly.
4607 sort_track_selection (ts);
4610 if (!entered_track) {
4613 ts.push_back (entered_track);
4616 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4617 (*i)->cut_copy_clear (*selection, op);
4622 Editor::paste (float times, bool from_context)
4624 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4626 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4630 Editor::mouse_paste ()
4635 if (!mouse_frame (where, ignored)) {
4640 paste_internal (where, 1);
4644 Editor::paste_internal (framepos_t position, float times)
4646 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4648 if (cut_buffer->empty(internal_editing())) {
4652 if (position == max_framepos) {
4653 position = get_preferred_edit_position();
4654 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4657 if (position == last_paste_pos) {
4658 /* repeated paste in the same position */
4661 /* paste in new location, reset repeated paste state */
4663 last_paste_pos = position;
4666 /* get everything in the correct order */
4669 if (!selection->tracks.empty()) {
4670 /* If there is a track selection, paste into exactly those tracks and
4671 only those tracks. This allows the user to be explicit and override
4672 the below "do the reasonable thing" logic. */
4673 ts = selection->tracks.filter_to_unique_playlists ();
4674 sort_track_selection (ts);
4676 /* Figure out which track to base the paste at. */
4677 TimeAxisView* base_track = NULL;
4678 if (_edit_point == Editing::EditAtMouse && entered_track) {
4679 /* With the mouse edit point, paste onto the track under the mouse. */
4680 base_track = entered_track;
4681 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4682 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4683 base_track = &entered_regionview->get_time_axis_view();
4684 } else if (_last_cut_copy_source_track) {
4685 /* Paste to the track that the cut/copy came from (see mantis #333). */
4686 base_track = _last_cut_copy_source_track;
4688 /* This is "impossible" since we've copied... well, do nothing. */
4692 /* Walk up to parent if necessary, so base track is a route. */
4693 while (base_track->get_parent()) {
4694 base_track = base_track->get_parent();
4697 /* Add base track and all tracks below it. The paste logic will select
4698 the appropriate object types from the cut buffer in relative order. */
4699 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4700 if ((*i)->order() >= base_track->order()) {
4705 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4706 sort_track_selection (ts);
4708 /* Add automation children of each track in order, for pasting several lines. */
4709 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4710 /* Add any automation children for pasting several lines */
4711 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4716 typedef RouteTimeAxisView::AutomationTracks ATracks;
4717 const ATracks& atracks = rtv->automation_tracks();
4718 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4719 i = ts.insert(i, a->second.get());
4724 /* We now have a list of trackviews starting at base_track, including
4725 automation children, in the order shown in the editor, e.g. R1,
4726 R1.A1, R1.A2, R2, R2.A1, ... */
4729 begin_reversible_command (Operations::paste);
4731 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4732 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4733 /* Only one line copied, and one automation track selected. Do a
4734 "greedy" paste from one automation type to another. */
4736 PasteContext ctx(paste_count, times, ItemCounts(), true);
4737 ts.front()->paste (position, *cut_buffer, ctx);
4741 /* Paste into tracks */
4743 PasteContext ctx(paste_count, times, ItemCounts(), false);
4744 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4745 (*i)->paste (position, *cut_buffer, ctx);
4749 commit_reversible_command ();
4753 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4755 if (regions.empty ()) {
4759 boost::shared_ptr<Playlist> playlist;
4760 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4761 RegionSelection foo;
4763 framepos_t const start_frame = regions.start ();
4764 framepos_t const end_frame = regions.end_frame ();
4765 framecnt_t const gap = end_frame - start_frame + 1;
4767 begin_reversible_command (Operations::duplicate_region);
4769 selection->clear_regions ();
4771 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4773 boost::shared_ptr<Region> r ((*i)->region());
4775 TimeAxisView& tv = (*i)->get_time_axis_view();
4776 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4777 latest_regionviews.clear ();
4778 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4780 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4781 playlist = (*i)->region()->playlist();
4782 playlist->clear_changes ();
4783 playlist->duplicate (r, position, gap, times);
4784 _session->add_command(new StatefulDiffCommand (playlist));
4788 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4792 selection->set (foo);
4795 commit_reversible_command ();
4799 Editor::duplicate_selection (float times)
4801 if (selection->time.empty() || selection->tracks.empty()) {
4805 boost::shared_ptr<Playlist> playlist;
4806 vector<boost::shared_ptr<Region> > new_regions;
4807 vector<boost::shared_ptr<Region> >::iterator ri;
4809 create_region_from_selection (new_regions);
4811 if (new_regions.empty()) {
4815 ri = new_regions.begin();
4817 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4818 bool in_command = false;
4820 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4821 if ((playlist = (*i)->playlist()) == 0) {
4824 playlist->clear_changes ();
4826 if (clicked_selection) {
4827 end = selection->time[clicked_selection].end;
4829 end = selection->time.end_frame();
4831 playlist->duplicate (*ri, end + 1, times);
4834 begin_reversible_command (_("duplicate selection"));
4837 _session->add_command (new StatefulDiffCommand (playlist));
4840 if (ri == new_regions.end()) {
4846 commit_reversible_command ();
4850 /** Reset all selected points to the relevant default value */
4852 Editor::reset_point_selection ()
4854 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4855 ARDOUR::AutomationList::iterator j = (*i)->model ();
4856 (*j)->value = (*i)->line().the_list()->default_value ();
4861 Editor::center_playhead ()
4863 float const page = _visible_canvas_width * samples_per_pixel;
4864 center_screen_internal (playhead_cursor->current_frame (), page);
4868 Editor::center_edit_point ()
4870 float const page = _visible_canvas_width * samples_per_pixel;
4871 center_screen_internal (get_preferred_edit_position(), page);
4874 /** Caller must begin and commit a reversible command */
4876 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4878 playlist->clear_changes ();
4880 _session->add_command (new StatefulDiffCommand (playlist));
4884 Editor::nudge_track (bool use_edit, bool forwards)
4886 boost::shared_ptr<Playlist> playlist;
4887 framepos_t distance;
4888 framepos_t next_distance;
4892 start = get_preferred_edit_position();
4897 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4901 if (selection->tracks.empty()) {
4905 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4906 bool in_command = false;
4908 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4910 if ((playlist = (*i)->playlist()) == 0) {
4914 playlist->clear_changes ();
4915 playlist->clear_owned_changes ();
4917 playlist->nudge_after (start, distance, forwards);
4920 begin_reversible_command (_("nudge track"));
4923 vector<Command*> cmds;
4925 playlist->rdiff (cmds);
4926 _session->add_commands (cmds);
4928 _session->add_command (new StatefulDiffCommand (playlist));
4932 commit_reversible_command ();
4937 Editor::remove_last_capture ()
4939 vector<string> choices;
4946 if (Config->get_verify_remove_last_capture()) {
4947 prompt = _("Do you really want to destroy the last capture?"
4948 "\n(This is destructive and cannot be undone)");
4950 choices.push_back (_("No, do nothing."));
4951 choices.push_back (_("Yes, destroy it."));
4953 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4955 if (prompter.run () == 1) {
4956 _session->remove_last_capture ();
4957 _regions->redisplay ();
4961 _session->remove_last_capture();
4962 _regions->redisplay ();
4967 Editor::normalize_region ()
4973 RegionSelection rs = get_regions_from_selection_and_entered ();
4979 NormalizeDialog dialog (rs.size() > 1);
4981 if (dialog.run () == RESPONSE_CANCEL) {
4985 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4988 /* XXX: should really only count audio regions here */
4989 int const regions = rs.size ();
4991 /* Make a list of the selected audio regions' maximum amplitudes, and also
4992 obtain the maximum amplitude of them all.
4994 list<double> max_amps;
4996 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4997 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4999 dialog.descend (1.0 / regions);
5000 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5003 /* the user cancelled the operation */
5007 max_amps.push_back (a);
5008 max_amp = max (max_amp, a);
5013 list<double>::const_iterator a = max_amps.begin ();
5014 bool in_command = false;
5016 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5017 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5022 arv->region()->clear_changes ();
5024 double const amp = dialog.normalize_individually() ? *a : max_amp;
5026 arv->audio_region()->normalize (amp, dialog.target ());
5029 begin_reversible_command (_("normalize"));
5032 _session->add_command (new StatefulDiffCommand (arv->region()));
5038 commit_reversible_command ();
5044 Editor::reset_region_scale_amplitude ()
5050 RegionSelection rs = get_regions_from_selection_and_entered ();
5056 bool in_command = false;
5058 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5059 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5062 arv->region()->clear_changes ();
5063 arv->audio_region()->set_scale_amplitude (1.0f);
5066 begin_reversible_command ("reset gain");
5069 _session->add_command (new StatefulDiffCommand (arv->region()));
5073 commit_reversible_command ();
5078 Editor::adjust_region_gain (bool up)
5080 RegionSelection rs = get_regions_from_selection_and_entered ();
5082 if (!_session || rs.empty()) {
5086 bool in_command = false;
5088 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5089 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5094 arv->region()->clear_changes ();
5096 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5104 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5107 begin_reversible_command ("adjust region gain");
5110 _session->add_command (new StatefulDiffCommand (arv->region()));
5114 commit_reversible_command ();
5120 Editor::reverse_region ()
5126 Reverse rev (*_session);
5127 apply_filter (rev, _("reverse regions"));
5131 Editor::strip_region_silence ()
5137 RegionSelection rs = get_regions_from_selection_and_entered ();
5143 std::list<RegionView*> audio_only;
5145 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5146 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5148 audio_only.push_back (arv);
5152 assert (!audio_only.empty());
5154 StripSilenceDialog d (_session, audio_only);
5155 int const r = d.run ();
5159 if (r == Gtk::RESPONSE_OK) {
5160 ARDOUR::AudioIntervalMap silences;
5161 d.silences (silences);
5162 StripSilence s (*_session, silences, d.fade_length());
5163 apply_filter (s, _("strip silence"), &d);
5168 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5170 Evoral::Sequence<Evoral::Beats>::Notes selected;
5171 mrv.selection_as_notelist (selected, true);
5173 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5174 v.push_back (selected);
5176 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5177 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5179 return op (mrv.midi_region()->model(), pos_beats, v);
5183 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5189 bool in_command = false;
5191 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5192 RegionSelection::const_iterator tmp = r;
5195 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5198 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5201 begin_reversible_command (op.name ());
5205 _session->add_command (cmd);
5213 commit_reversible_command ();
5218 Editor::fork_region ()
5220 RegionSelection rs = get_regions_from_selection_and_entered ();
5226 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5227 bool in_command = false;
5231 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5232 RegionSelection::iterator tmp = r;
5235 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5239 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5240 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5241 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5244 begin_reversible_command (_("Fork Region(s)"));
5247 playlist->clear_changes ();
5248 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5249 _session->add_command(new StatefulDiffCommand (playlist));
5251 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5259 commit_reversible_command ();
5264 Editor::quantize_region ()
5267 quantize_regions(get_regions_from_selection_and_entered ());
5272 Editor::quantize_regions (const RegionSelection& rs)
5274 if (rs.n_midi_regions() == 0) {
5278 if (!quantize_dialog) {
5279 quantize_dialog = new QuantizeDialog (*this);
5282 quantize_dialog->present ();
5283 const int r = quantize_dialog->run ();
5284 quantize_dialog->hide ();
5286 if (r == Gtk::RESPONSE_OK) {
5287 Quantize quant (quantize_dialog->snap_start(),
5288 quantize_dialog->snap_end(),
5289 quantize_dialog->start_grid_size(),
5290 quantize_dialog->end_grid_size(),
5291 quantize_dialog->strength(),
5292 quantize_dialog->swing(),
5293 quantize_dialog->threshold());
5295 apply_midi_note_edit_op (quant, rs);
5300 Editor::legatize_region (bool shrink_only)
5303 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5308 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5310 if (rs.n_midi_regions() == 0) {
5314 Legatize legatize(shrink_only);
5315 apply_midi_note_edit_op (legatize, rs);
5319 Editor::transform_region ()
5322 transform_regions(get_regions_from_selection_and_entered ());
5327 Editor::transform_regions (const RegionSelection& rs)
5329 if (rs.n_midi_regions() == 0) {
5336 const int r = td.run();
5339 if (r == Gtk::RESPONSE_OK) {
5340 Transform transform(td.get());
5341 apply_midi_note_edit_op(transform, rs);
5346 Editor::transpose_region ()
5349 transpose_regions(get_regions_from_selection_and_entered ());
5354 Editor::transpose_regions (const RegionSelection& rs)
5356 if (rs.n_midi_regions() == 0) {
5361 int const r = d.run ();
5363 if (r == RESPONSE_ACCEPT) {
5364 Transpose transpose(d.semitones ());
5365 apply_midi_note_edit_op (transpose, rs);
5370 Editor::insert_patch_change (bool from_context)
5372 RegionSelection rs = get_regions_from_selection_and_entered ();
5378 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5380 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5381 there may be more than one, but the PatchChangeDialog can only offer
5382 one set of patch menus.
5384 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5386 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5387 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5389 if (d.run() == RESPONSE_CANCEL) {
5393 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5394 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5396 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5397 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5404 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5406 RegionSelection rs = get_regions_from_selection_and_entered ();
5412 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5413 bool in_command = false;
5418 int const N = rs.size ();
5420 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5421 RegionSelection::iterator tmp = r;
5424 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5426 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5429 progress->descend (1.0 / N);
5432 if (arv->audio_region()->apply (filter, progress) == 0) {
5434 playlist->clear_changes ();
5435 playlist->clear_owned_changes ();
5437 if (filter.results.empty ()) {
5439 /* no regions returned; remove the old one */
5440 playlist->remove_region (arv->region ());
5444 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5446 /* first region replaces the old one */
5447 playlist->replace_region (arv->region(), *res, (*res)->position());
5451 while (res != filter.results.end()) {
5452 playlist->add_region (*res, (*res)->position());
5457 /* We might have removed regions, which alters other regions' layering_index,
5458 so we need to do a recursive diff here.
5462 begin_reversible_command (command);
5465 vector<Command*> cmds;
5466 playlist->rdiff (cmds);
5467 _session->add_commands (cmds);
5469 _session->add_command(new StatefulDiffCommand (playlist));
5473 progress->ascend ();
5482 commit_reversible_command ();
5487 Editor::external_edit_region ()
5493 Editor::reset_region_gain_envelopes ()
5495 RegionSelection rs = get_regions_from_selection_and_entered ();
5497 if (!_session || rs.empty()) {
5501 bool in_command = false;
5503 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5504 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5506 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5507 XMLNode& before (alist->get_state());
5509 arv->audio_region()->set_default_envelope ();
5512 begin_reversible_command (_("reset region gain"));
5515 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5520 commit_reversible_command ();
5525 Editor::set_region_gain_visibility (RegionView* rv)
5527 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5529 arv->update_envelope_visibility();
5534 Editor::set_gain_envelope_visibility ()
5540 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5541 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5543 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5549 Editor::toggle_gain_envelope_active ()
5551 if (_ignore_region_action) {
5555 RegionSelection rs = get_regions_from_selection_and_entered ();
5557 if (!_session || rs.empty()) {
5561 bool in_command = false;
5563 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5564 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5566 arv->region()->clear_changes ();
5567 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5570 begin_reversible_command (_("region gain envelope active"));
5573 _session->add_command (new StatefulDiffCommand (arv->region()));
5578 commit_reversible_command ();
5583 Editor::toggle_region_lock ()
5585 if (_ignore_region_action) {
5589 RegionSelection rs = get_regions_from_selection_and_entered ();
5591 if (!_session || rs.empty()) {
5595 begin_reversible_command (_("toggle region lock"));
5597 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5598 (*i)->region()->clear_changes ();
5599 (*i)->region()->set_locked (!(*i)->region()->locked());
5600 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5603 commit_reversible_command ();
5607 Editor::toggle_region_video_lock ()
5609 if (_ignore_region_action) {
5613 RegionSelection rs = get_regions_from_selection_and_entered ();
5615 if (!_session || rs.empty()) {
5619 begin_reversible_command (_("Toggle Video Lock"));
5621 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5622 (*i)->region()->clear_changes ();
5623 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5624 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5627 commit_reversible_command ();
5631 Editor::toggle_region_lock_style ()
5633 if (_ignore_region_action) {
5637 RegionSelection rs = get_regions_from_selection_and_entered ();
5639 if (!_session || rs.empty()) {
5643 begin_reversible_command (_("region lock style"));
5645 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5646 (*i)->region()->clear_changes ();
5647 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5648 (*i)->region()->set_position_lock_style (ns);
5649 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5652 commit_reversible_command ();
5656 Editor::toggle_opaque_region ()
5658 if (_ignore_region_action) {
5662 RegionSelection rs = get_regions_from_selection_and_entered ();
5664 if (!_session || rs.empty()) {
5668 begin_reversible_command (_("change region opacity"));
5670 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5671 (*i)->region()->clear_changes ();
5672 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5673 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5676 commit_reversible_command ();
5680 Editor::toggle_record_enable ()
5682 bool new_state = false;
5684 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5685 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5688 if (!rtav->is_track())
5692 new_state = !rtav->track()->record_enabled();
5696 rtav->track()->set_record_enabled (new_state, this);
5701 Editor::toggle_solo ()
5703 bool new_state = false;
5705 boost::shared_ptr<RouteList> rl (new RouteList);
5707 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5708 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5715 new_state = !rtav->route()->soloed ();
5719 rl->push_back (rtav->route());
5722 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5726 Editor::toggle_mute ()
5728 bool new_state = false;
5730 boost::shared_ptr<RouteList> rl (new RouteList);
5732 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5733 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5740 new_state = !rtav->route()->muted();
5744 rl->push_back (rtav->route());
5747 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5751 Editor::toggle_solo_isolate ()
5757 Editor::fade_range ()
5759 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5761 begin_reversible_command (_("fade range"));
5763 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5764 (*i)->fade_range (selection->time);
5767 commit_reversible_command ();
5772 Editor::set_fade_length (bool in)
5774 RegionSelection rs = get_regions_from_selection_and_entered ();
5780 /* we need a region to measure the offset from the start */
5782 RegionView* rv = rs.front ();
5784 framepos_t pos = get_preferred_edit_position();
5788 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5789 /* edit point is outside the relevant region */
5794 if (pos <= rv->region()->position()) {
5798 len = pos - rv->region()->position();
5799 cmd = _("set fade in length");
5801 if (pos >= rv->region()->last_frame()) {
5805 len = rv->region()->last_frame() - pos;
5806 cmd = _("set fade out length");
5809 bool in_command = false;
5811 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5812 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5818 boost::shared_ptr<AutomationList> alist;
5820 alist = tmp->audio_region()->fade_in();
5822 alist = tmp->audio_region()->fade_out();
5825 XMLNode &before = alist->get_state();
5828 tmp->audio_region()->set_fade_in_length (len);
5829 tmp->audio_region()->set_fade_in_active (true);
5831 tmp->audio_region()->set_fade_out_length (len);
5832 tmp->audio_region()->set_fade_out_active (true);
5836 begin_reversible_command (cmd);
5839 XMLNode &after = alist->get_state();
5840 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5844 commit_reversible_command ();
5849 Editor::set_fade_in_shape (FadeShape shape)
5851 RegionSelection rs = get_regions_from_selection_and_entered ();
5856 bool in_command = false;
5858 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5859 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5865 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5866 XMLNode &before = alist->get_state();
5868 tmp->audio_region()->set_fade_in_shape (shape);
5871 begin_reversible_command (_("set fade in shape"));
5874 XMLNode &after = alist->get_state();
5875 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5879 commit_reversible_command ();
5884 Editor::set_fade_out_shape (FadeShape shape)
5886 RegionSelection rs = get_regions_from_selection_and_entered ();
5891 bool in_command = false;
5893 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5894 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5900 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5901 XMLNode &before = alist->get_state();
5903 tmp->audio_region()->set_fade_out_shape (shape);
5906 begin_reversible_command (_("set fade out shape"));
5909 XMLNode &after = alist->get_state();
5910 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5914 commit_reversible_command ();
5919 Editor::set_fade_in_active (bool yn)
5921 RegionSelection rs = get_regions_from_selection_and_entered ();
5926 bool in_command = false;
5928 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5929 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5936 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5938 ar->clear_changes ();
5939 ar->set_fade_in_active (yn);
5942 begin_reversible_command (_("set fade in active"));
5945 _session->add_command (new StatefulDiffCommand (ar));
5949 commit_reversible_command ();
5954 Editor::set_fade_out_active (bool yn)
5956 RegionSelection rs = get_regions_from_selection_and_entered ();
5961 bool in_command = false;
5963 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5964 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5970 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5972 ar->clear_changes ();
5973 ar->set_fade_out_active (yn);
5976 begin_reversible_command (_("set fade out active"));
5979 _session->add_command(new StatefulDiffCommand (ar));
5983 commit_reversible_command ();
5988 Editor::toggle_region_fades (int dir)
5990 if (_ignore_region_action) {
5994 boost::shared_ptr<AudioRegion> ar;
5997 RegionSelection rs = get_regions_from_selection_and_entered ();
6003 RegionSelection::iterator i;
6004 for (i = rs.begin(); i != rs.end(); ++i) {
6005 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6007 yn = ar->fade_out_active ();
6009 yn = ar->fade_in_active ();
6015 if (i == rs.end()) {
6019 /* XXX should this undo-able? */
6020 bool in_command = false;
6022 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6023 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6026 ar->clear_changes ();
6028 if (dir == 1 || dir == 0) {
6029 ar->set_fade_in_active (!yn);
6032 if (dir == -1 || dir == 0) {
6033 ar->set_fade_out_active (!yn);
6036 begin_reversible_command (_("toggle fade active"));
6039 _session->add_command(new StatefulDiffCommand (ar));
6043 commit_reversible_command ();
6048 /** Update region fade visibility after its configuration has been changed */
6050 Editor::update_region_fade_visibility ()
6052 bool _fade_visibility = _session->config.get_show_region_fades ();
6054 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6055 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6057 if (_fade_visibility) {
6058 v->audio_view()->show_all_fades ();
6060 v->audio_view()->hide_all_fades ();
6067 Editor::set_edit_point ()
6072 if (!mouse_frame (where, ignored)) {
6078 if (selection->markers.empty()) {
6080 mouse_add_new_marker (where);
6085 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6088 loc->move_to (where);
6094 Editor::set_playhead_cursor ()
6096 if (entered_marker) {
6097 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6102 if (!mouse_frame (where, ignored)) {
6109 _session->request_locate (where, _session->transport_rolling());
6113 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6114 cancel_time_selection();
6119 Editor::split_region ()
6121 if (_drags->active ()) {
6125 //if a range is selected, separate it
6126 if ( !selection->time.empty()) {
6127 separate_regions_between (selection->time);
6131 //if no range was selected, try to find some regions to split
6132 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6134 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6136 framepos_t where = get_preferred_edit_position ();
6142 split_regions_at (where, rs);
6146 struct EditorOrderRouteSorter {
6147 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6148 return a->order_key () < b->order_key ();
6153 Editor::select_next_route()
6155 if (selection->tracks.empty()) {
6156 selection->set (track_views.front());
6160 TimeAxisView* current = selection->tracks.front();
6164 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6165 if (*i == current) {
6167 if (i != track_views.end()) {
6170 current = (*(track_views.begin()));
6171 //selection->set (*(track_views.begin()));
6176 rui = dynamic_cast<RouteUI *>(current);
6177 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6179 selection->set(current);
6181 ensure_time_axis_view_is_visible (*current, false);
6185 Editor::select_prev_route()
6187 if (selection->tracks.empty()) {
6188 selection->set (track_views.front());
6192 TimeAxisView* current = selection->tracks.front();
6196 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6197 if (*i == current) {
6199 if (i != track_views.rend()) {
6202 current = *(track_views.rbegin());
6207 rui = dynamic_cast<RouteUI *>(current);
6208 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6210 selection->set (current);
6212 ensure_time_axis_view_is_visible (*current, false);
6216 Editor::set_loop_from_selection (bool play)
6218 if (_session == 0) {
6222 framepos_t start, end;
6223 if (!get_selection_extents ( start, end))
6226 set_loop_range (start, end, _("set loop range from selection"));
6229 _session->request_play_loop (true, true);
6234 Editor::set_loop_from_region (bool play)
6236 framepos_t start, end;
6237 if (!get_selection_extents ( start, end))
6240 set_loop_range (start, end, _("set loop range from region"));
6243 _session->request_locate (start, true);
6244 _session->request_play_loop (true);
6249 Editor::set_punch_from_selection ()
6251 if (_session == 0) {
6255 framepos_t start, end;
6256 if (!get_selection_extents ( start, end))
6259 set_punch_range (start, end, _("set punch range from selection"));
6263 Editor::set_session_extents_from_selection ()
6265 if (_session == 0) {
6269 framepos_t start, end;
6270 if (!get_selection_extents ( start, end))
6274 if ((loc = _session->locations()->session_range_location()) == 0) {
6275 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6277 XMLNode &before = loc->get_state();
6279 _session->set_session_extents ( start, end );
6281 XMLNode &after = loc->get_state();
6283 begin_reversible_command (_("set session start/end from selection"));
6285 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6287 commit_reversible_command ();
6292 Editor::set_punch_start_from_edit_point ()
6296 framepos_t start = 0;
6297 framepos_t end = max_framepos;
6299 //use the existing punch end, if any
6300 Location* tpl = transport_punch_location();
6305 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6306 start = _session->audible_frame();
6308 start = get_preferred_edit_position();
6311 //snap the selection start/end
6314 //if there's not already a sensible selection endpoint, go "forever"
6315 if ( start > end ) {
6319 set_punch_range (start, end, _("set punch start from EP"));
6325 Editor::set_punch_end_from_edit_point ()
6329 framepos_t start = 0;
6330 framepos_t end = max_framepos;
6332 //use the existing punch start, if any
6333 Location* tpl = transport_punch_location();
6335 start = tpl->start();
6338 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6339 end = _session->audible_frame();
6341 end = get_preferred_edit_position();
6344 //snap the selection start/end
6347 set_punch_range (start, end, _("set punch end from EP"));
6353 Editor::set_loop_start_from_edit_point ()
6357 framepos_t start = 0;
6358 framepos_t end = max_framepos;
6360 //use the existing loop end, if any
6361 Location* tpl = transport_loop_location();
6366 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6367 start = _session->audible_frame();
6369 start = get_preferred_edit_position();
6372 //snap the selection start/end
6375 //if there's not already a sensible selection endpoint, go "forever"
6376 if ( start > end ) {
6380 set_loop_range (start, end, _("set loop start from EP"));
6386 Editor::set_loop_end_from_edit_point ()
6390 framepos_t start = 0;
6391 framepos_t end = max_framepos;
6393 //use the existing loop start, if any
6394 Location* tpl = transport_loop_location();
6396 start = tpl->start();
6399 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6400 end = _session->audible_frame();
6402 end = get_preferred_edit_position();
6405 //snap the selection start/end
6408 set_loop_range (start, end, _("set loop end from EP"));
6413 Editor::set_punch_from_region ()
6415 framepos_t start, end;
6416 if (!get_selection_extents ( start, end))
6419 set_punch_range (start, end, _("set punch range from region"));
6423 Editor::pitch_shift_region ()
6425 RegionSelection rs = get_regions_from_selection_and_entered ();
6427 RegionSelection audio_rs;
6428 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6429 if (dynamic_cast<AudioRegionView*> (*i)) {
6430 audio_rs.push_back (*i);
6434 if (audio_rs.empty()) {
6438 pitch_shift (audio_rs, 1.2);
6442 Editor::set_tempo_from_region ()
6444 RegionSelection rs = get_regions_from_selection_and_entered ();
6446 if (!_session || rs.empty()) {
6450 RegionView* rv = rs.front();
6452 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6456 Editor::use_range_as_bar ()
6458 framepos_t start, end;
6459 if (get_edit_op_range (start, end)) {
6460 define_one_bar (start, end);
6465 Editor::define_one_bar (framepos_t start, framepos_t end)
6467 framepos_t length = end - start;
6469 const Meter& m (_session->tempo_map().meter_at (start));
6471 /* length = 1 bar */
6473 /* now we want frames per beat.
6474 we have frames per bar, and beats per bar, so ...
6477 /* XXXX METER MATH */
6479 double frames_per_beat = length / m.divisions_per_bar();
6481 /* beats per minute = */
6483 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6485 /* now decide whether to:
6487 (a) set global tempo
6488 (b) add a new tempo marker
6492 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6494 bool do_global = false;
6496 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6498 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6499 at the start, or create a new marker
6502 vector<string> options;
6503 options.push_back (_("Cancel"));
6504 options.push_back (_("Add new marker"));
6505 options.push_back (_("Set global tempo"));
6508 _("Define one bar"),
6509 _("Do you want to set the global tempo or add a new tempo marker?"),
6513 c.set_default_response (2);
6529 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6530 if the marker is at the region starter, change it, otherwise add
6535 begin_reversible_command (_("set tempo from region"));
6536 XMLNode& before (_session->tempo_map().get_state());
6539 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6540 } else if (t.frame() == start) {
6541 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6543 Timecode::BBT_Time bbt;
6544 _session->tempo_map().bbt_time (start, bbt);
6545 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6548 XMLNode& after (_session->tempo_map().get_state());
6550 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6551 commit_reversible_command ();
6555 Editor::split_region_at_transients ()
6557 AnalysisFeatureList positions;
6559 RegionSelection rs = get_regions_from_selection_and_entered ();
6561 if (!_session || rs.empty()) {
6565 begin_reversible_command (_("split regions"));
6567 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6569 RegionSelection::iterator tmp;
6574 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6576 if (ar && (ar->get_transients (positions) == 0)) {
6577 split_region_at_points ((*i)->region(), positions, true);
6584 commit_reversible_command ();
6589 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6591 bool use_rhythmic_rodent = false;
6593 boost::shared_ptr<Playlist> pl = r->playlist();
6595 list<boost::shared_ptr<Region> > new_regions;
6601 if (positions.empty()) {
6606 if (positions.size() > 20 && can_ferret) {
6607 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);
6608 MessageDialog msg (msgstr,
6611 Gtk::BUTTONS_OK_CANCEL);
6614 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6615 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6617 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6620 msg.set_title (_("Excessive split?"));
6623 int response = msg.run();
6629 case RESPONSE_APPLY:
6630 use_rhythmic_rodent = true;
6637 if (use_rhythmic_rodent) {
6638 show_rhythm_ferret ();
6642 AnalysisFeatureList::const_iterator x;
6644 pl->clear_changes ();
6645 pl->clear_owned_changes ();
6647 x = positions.begin();
6649 if (x == positions.end()) {
6654 pl->remove_region (r);
6658 while (x != positions.end()) {
6660 /* deal with positons that are out of scope of present region bounds */
6661 if (*x <= 0 || *x > r->length()) {
6666 /* file start = original start + how far we from the initial position ?
6669 framepos_t file_start = r->start() + pos;
6671 /* length = next position - current position
6674 framepos_t len = (*x) - pos;
6676 /* XXX we do we really want to allow even single-sample regions?
6677 shouldn't we have some kind of lower limit on region size?
6686 if (RegionFactory::region_name (new_name, r->name())) {
6690 /* do NOT announce new regions 1 by one, just wait till they are all done */
6694 plist.add (ARDOUR::Properties::start, file_start);
6695 plist.add (ARDOUR::Properties::length, len);
6696 plist.add (ARDOUR::Properties::name, new_name);
6697 plist.add (ARDOUR::Properties::layer, 0);
6699 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6700 /* because we set annouce to false, manually add the new region to the
6703 RegionFactory::map_add (nr);
6705 pl->add_region (nr, r->position() + pos);
6708 new_regions.push_front(nr);
6717 RegionFactory::region_name (new_name, r->name());
6719 /* Add the final region */
6722 plist.add (ARDOUR::Properties::start, r->start() + pos);
6723 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6724 plist.add (ARDOUR::Properties::name, new_name);
6725 plist.add (ARDOUR::Properties::layer, 0);
6727 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6728 /* because we set annouce to false, manually add the new region to the
6731 RegionFactory::map_add (nr);
6732 pl->add_region (nr, r->position() + pos);
6735 new_regions.push_front(nr);
6740 /* We might have removed regions, which alters other regions' layering_index,
6741 so we need to do a recursive diff here.
6743 vector<Command*> cmds;
6745 _session->add_commands (cmds);
6747 _session->add_command (new StatefulDiffCommand (pl));
6751 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6752 set_selected_regionview_from_region_list ((*i), Selection::Add);
6758 Editor::place_transient()
6764 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6770 framepos_t where = get_preferred_edit_position();
6772 begin_reversible_command (_("place transient"));
6774 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6775 framepos_t position = (*r)->region()->position();
6776 (*r)->region()->add_transient(where - position);
6779 commit_reversible_command ();
6783 Editor::remove_transient(ArdourCanvas::Item* item)
6789 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6792 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6793 _arv->remove_transient (*(float*) _line->get_data ("position"));
6797 Editor::snap_regions_to_grid ()
6799 list <boost::shared_ptr<Playlist > > used_playlists;
6801 RegionSelection rs = get_regions_from_selection_and_entered ();
6803 if (!_session || rs.empty()) {
6807 begin_reversible_command (_("snap regions to grid"));
6809 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6811 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6813 if (!pl->frozen()) {
6814 /* we haven't seen this playlist before */
6816 /* remember used playlists so we can thaw them later */
6817 used_playlists.push_back(pl);
6821 framepos_t start_frame = (*r)->region()->first_frame ();
6822 snap_to (start_frame);
6823 (*r)->region()->set_position (start_frame);
6826 while (used_playlists.size() > 0) {
6827 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6829 used_playlists.pop_front();
6832 commit_reversible_command ();
6836 Editor::close_region_gaps ()
6838 list <boost::shared_ptr<Playlist > > used_playlists;
6840 RegionSelection rs = get_regions_from_selection_and_entered ();
6842 if (!_session || rs.empty()) {
6846 Dialog dialog (_("Close Region Gaps"));
6849 table.set_spacings (12);
6850 table.set_border_width (12);
6851 Label* l = manage (left_aligned_label (_("Crossfade length")));
6852 table.attach (*l, 0, 1, 0, 1);
6854 SpinButton spin_crossfade (1, 0);
6855 spin_crossfade.set_range (0, 15);
6856 spin_crossfade.set_increments (1, 1);
6857 spin_crossfade.set_value (5);
6858 table.attach (spin_crossfade, 1, 2, 0, 1);
6860 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6862 l = manage (left_aligned_label (_("Pull-back length")));
6863 table.attach (*l, 0, 1, 1, 2);
6865 SpinButton spin_pullback (1, 0);
6866 spin_pullback.set_range (0, 100);
6867 spin_pullback.set_increments (1, 1);
6868 spin_pullback.set_value(30);
6869 table.attach (spin_pullback, 1, 2, 1, 2);
6871 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6873 dialog.get_vbox()->pack_start (table);
6874 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6875 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6878 if (dialog.run () == RESPONSE_CANCEL) {
6882 framepos_t crossfade_len = spin_crossfade.get_value();
6883 framepos_t pull_back_frames = spin_pullback.get_value();
6885 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6886 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6888 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6890 begin_reversible_command (_("close region gaps"));
6893 boost::shared_ptr<Region> last_region;
6895 rs.sort_by_position_and_track();
6897 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6899 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6901 if (!pl->frozen()) {
6902 /* we haven't seen this playlist before */
6904 /* remember used playlists so we can thaw them later */
6905 used_playlists.push_back(pl);
6909 framepos_t position = (*r)->region()->position();
6911 if (idx == 0 || position < last_region->position()){
6912 last_region = (*r)->region();
6917 (*r)->region()->trim_front( (position - pull_back_frames));
6918 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6920 last_region = (*r)->region();
6925 while (used_playlists.size() > 0) {
6926 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6928 used_playlists.pop_front();
6931 commit_reversible_command ();
6935 Editor::tab_to_transient (bool forward)
6937 AnalysisFeatureList positions;
6939 RegionSelection rs = get_regions_from_selection_and_entered ();
6945 framepos_t pos = _session->audible_frame ();
6947 if (!selection->tracks.empty()) {
6949 /* don't waste time searching for transients in duplicate playlists.
6952 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6954 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6956 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6959 boost::shared_ptr<Track> tr = rtv->track();
6961 boost::shared_ptr<Playlist> pl = tr->playlist ();
6963 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6966 positions.push_back (result);
6979 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6980 (*r)->region()->get_transients (positions);
6984 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6987 AnalysisFeatureList::iterator x;
6989 for (x = positions.begin(); x != positions.end(); ++x) {
6995 if (x != positions.end ()) {
6996 _session->request_locate (*x);
7000 AnalysisFeatureList::reverse_iterator x;
7002 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7008 if (x != positions.rend ()) {
7009 _session->request_locate (*x);
7015 Editor::playhead_forward_to_grid ()
7021 framepos_t pos = playhead_cursor->current_frame ();
7022 if (pos < max_framepos - 1) {
7024 snap_to_internal (pos, RoundUpAlways, false);
7025 _session->request_locate (pos);
7031 Editor::playhead_backward_to_grid ()
7037 framepos_t pos = playhead_cursor->current_frame ();
7040 snap_to_internal (pos, RoundDownAlways, false);
7041 _session->request_locate (pos);
7046 Editor::set_track_height (Height h)
7048 TrackSelection& ts (selection->tracks);
7050 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7051 (*x)->set_height_enum (h);
7056 Editor::toggle_tracks_active ()
7058 TrackSelection& ts (selection->tracks);
7060 bool target = false;
7066 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7067 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7071 target = !rtv->_route->active();
7074 rtv->_route->set_active (target, this);
7080 Editor::remove_tracks ()
7082 /* this will delete GUI objects that may be the subject of an event
7083 handler in which this method is called. Defer actual deletion to the
7084 next idle callback, when all event handling is finished.
7086 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7090 Editor::idle_remove_tracks ()
7093 return false; /* do not call again */
7097 Editor::_remove_tracks ()
7099 TrackSelection& ts (selection->tracks);
7105 vector<string> choices;
7109 const char* trackstr;
7111 vector<boost::shared_ptr<Route> > routes;
7112 bool special_bus = false;
7114 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7115 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7119 if (rtv->is_track()) {
7124 routes.push_back (rtv->_route);
7126 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7131 if (special_bus && !Config->get_allow_special_bus_removal()) {
7132 MessageDialog msg (_("That would be bad news ...."),
7136 msg.set_secondary_text (string_compose (_(
7137 "Removing the master or monitor bus is such a bad idea\n\
7138 that %1 is not going to allow it.\n\
7140 If you really want to do this sort of thing\n\
7141 edit your ardour.rc file to set the\n\
7142 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7149 if (ntracks + nbusses == 0) {
7153 trackstr = P_("track", "tracks", ntracks);
7154 busstr = P_("bus", "busses", nbusses);
7158 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7159 "(You may also lose the playlists associated with the %2)\n\n"
7160 "This action cannot be undone, and the session file will be overwritten!"),
7161 ntracks, trackstr, nbusses, busstr);
7163 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7164 "(You may also lose the playlists associated with the %2)\n\n"
7165 "This action cannot be undone, and the session file will be overwritten!"),
7168 } else if (nbusses) {
7169 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7170 "This action cannot be undone, and the session file will be overwritten"),
7174 choices.push_back (_("No, do nothing."));
7175 if (ntracks + nbusses > 1) {
7176 choices.push_back (_("Yes, remove them."));
7178 choices.push_back (_("Yes, remove it."));
7183 title = string_compose (_("Remove %1"), trackstr);
7185 title = string_compose (_("Remove %1"), busstr);
7188 Choice prompter (title, prompt, choices);
7190 if (prompter.run () != 1) {
7195 Session::StateProtector sp (_session);
7196 DisplaySuspender ds;
7197 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7198 _session->remove_route (*x);
7204 Editor::do_insert_time ()
7206 if (selection->tracks.empty()) {
7210 InsertRemoveTimeDialog d (*this);
7211 int response = d.run ();
7213 if (response != RESPONSE_OK) {
7217 if (d.distance() == 0) {
7221 InsertTimeOption opt = d.intersected_region_action ();
7224 get_preferred_edit_position(),
7230 d.move_glued_markers(),
7231 d.move_locked_markers(),
7237 Editor::insert_time (
7238 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7239 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7243 if (Config->get_edit_mode() == Lock) {
7246 bool in_command = false;
7248 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7250 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7254 /* don't operate on any playlist more than once, which could
7255 * happen if "all playlists" is enabled, but there is more
7256 * than 1 track using playlists "from" a given track.
7259 set<boost::shared_ptr<Playlist> > pl;
7261 if (all_playlists) {
7262 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7263 if (rtav && rtav->track ()) {
7264 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7265 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7270 if ((*x)->playlist ()) {
7271 pl.insert ((*x)->playlist ());
7275 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7277 (*i)->clear_changes ();
7278 (*i)->clear_owned_changes ();
7280 if (opt == SplitIntersected) {
7284 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7287 begin_reversible_command (_("insert time"));
7290 vector<Command*> cmds;
7292 _session->add_commands (cmds);
7294 _session->add_command (new StatefulDiffCommand (*i));
7298 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7301 begin_reversible_command (_("insert time"));
7304 rtav->route ()->shift (pos, frames);
7311 XMLNode& before (_session->locations()->get_state());
7312 Locations::LocationList copy (_session->locations()->list());
7314 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7316 Locations::LocationList::const_iterator tmp;
7318 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7319 bool const was_locked = (*i)->locked ();
7320 if (locked_markers_too) {
7324 if ((*i)->start() >= pos) {
7325 // move end first, in case we're moving by more than the length of the range
7326 if (!(*i)->is_mark()) {
7327 (*i)->set_end ((*i)->end() + frames);
7329 (*i)->set_start ((*i)->start() + frames);
7341 begin_reversible_command (_("insert time"));
7344 XMLNode& after (_session->locations()->get_state());
7345 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7351 begin_reversible_command (_("insert time"));
7354 XMLNode& before (_session->tempo_map().get_state());
7355 _session->tempo_map().insert_time (pos, frames);
7356 XMLNode& after (_session->tempo_map().get_state());
7357 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7361 commit_reversible_command ();
7366 Editor::do_remove_time ()
7368 if (selection->tracks.empty()) {
7372 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7373 InsertRemoveTimeDialog d (*this, true);
7375 int response = d.run ();
7377 if (response != RESPONSE_OK) {
7381 framecnt_t distance = d.distance();
7383 if (distance == 0) {
7393 d.move_glued_markers(),
7394 d.move_locked_markers(),
7400 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7401 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7403 if (Config->get_edit_mode() == Lock) {
7404 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7407 bool in_command = false;
7409 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7411 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7415 XMLNode &before = pl->get_state();
7417 std::list<AudioRange> rl;
7418 AudioRange ar(pos, pos+frames, 0);
7421 pl->shift (pos, -frames, true, ignore_music_glue);
7424 begin_reversible_command (_("cut time"));
7427 XMLNode &after = pl->get_state();
7429 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7433 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7436 begin_reversible_command (_("cut time"));
7439 rtav->route ()->shift (pos, -frames);
7443 std::list<Location*> loc_kill_list;
7448 XMLNode& before (_session->locations()->get_state());
7449 Locations::LocationList copy (_session->locations()->list());
7451 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7452 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7454 bool const was_locked = (*i)->locked ();
7455 if (locked_markers_too) {
7459 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7460 if ((*i)->end() >= pos
7461 && (*i)->end() < pos+frames
7462 && (*i)->start() >= pos
7463 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7465 loc_kill_list.push_back(*i);
7466 } else { // only start or end is included, try to do the right thing
7467 // move start before moving end, to avoid trying to move the end to before the start
7468 // if we're removing more time than the length of the range
7469 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7470 // start is within cut
7471 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7473 } else if ((*i)->start() >= pos+frames) {
7474 // start (and thus entire range) lies beyond end of cut
7475 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7478 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7479 // end is inside cut
7480 (*i)->set_end (pos); // bring the end to the cut
7482 } else if ((*i)->end() >= pos+frames) {
7483 // end is beyond end of cut
7484 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7489 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7490 loc_kill_list.push_back(*i);
7492 } else if ((*i)->start() >= pos) {
7493 (*i)->set_start ((*i)->start() -frames);
7503 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7504 _session->locations()->remove( *i );
7509 begin_reversible_command (_("cut time"));
7512 XMLNode& after (_session->locations()->get_state());
7513 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7518 XMLNode& before (_session->tempo_map().get_state());
7520 if (_session->tempo_map().remove_time (pos, frames) ) {
7522 begin_reversible_command (_("remove time"));
7525 XMLNode& after (_session->tempo_map().get_state());
7526 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7531 commit_reversible_command ();
7536 Editor::fit_selection ()
7538 if (!selection->tracks.empty()) {
7539 fit_tracks (selection->tracks);
7543 /* no selected tracks - use tracks with selected regions */
7545 if (!selection->regions.empty()) {
7546 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7547 tvl.push_back (&(*r)->get_time_axis_view ());
7553 } else if (internal_editing()) {
7554 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7557 if (entered_track) {
7558 tvl.push_back (entered_track);
7567 Editor::fit_tracks (TrackViewList & tracks)
7569 if (tracks.empty()) {
7573 uint32_t child_heights = 0;
7574 int visible_tracks = 0;
7576 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7578 if (!(*t)->marked_for_display()) {
7582 child_heights += (*t)->effective_height() - (*t)->current_height();
7586 /* compute the per-track height from:
7588 total canvas visible height -
7589 height that will be taken by visible children of selected
7590 tracks - height of the ruler/hscroll area
7592 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7593 double first_y_pos = DBL_MAX;
7595 if (h < TimeAxisView::preset_height (HeightSmall)) {
7596 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7597 /* too small to be displayed */
7601 undo_visual_stack.push_back (current_visual_state (true));
7602 PBD::Unwinder<bool> nsv (no_save_visual, true);
7604 /* build a list of all tracks, including children */
7607 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7609 TimeAxisView::Children c = (*i)->get_child_list ();
7610 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7611 all.push_back (j->get());
7616 // find selection range.
7617 // if someone knows how to user TrackViewList::iterator for this
7619 int selected_top = -1;
7620 int selected_bottom = -1;
7622 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7623 if ((*t)->marked_for_display ()) {
7624 if (tracks.contains(*t)) {
7625 if (selected_top == -1) {
7628 selected_bottom = i;
7634 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7635 if ((*t)->marked_for_display ()) {
7636 if (tracks.contains(*t)) {
7637 (*t)->set_height (h);
7638 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7640 if (i > selected_top && i < selected_bottom) {
7641 hide_track_in_display (*t);
7648 set the controls_layout height now, because waiting for its size
7649 request signal handler will cause the vertical adjustment setting to fail
7652 controls_layout.property_height () = _full_canvas_height;
7653 vertical_adjustment.set_value (first_y_pos);
7655 redo_visual_stack.push_back (current_visual_state (true));
7657 visible_tracks_selector.set_text (_("Sel"));
7661 Editor::save_visual_state (uint32_t n)
7663 while (visual_states.size() <= n) {
7664 visual_states.push_back (0);
7667 if (visual_states[n] != 0) {
7668 delete visual_states[n];
7671 visual_states[n] = current_visual_state (true);
7676 Editor::goto_visual_state (uint32_t n)
7678 if (visual_states.size() <= n) {
7682 if (visual_states[n] == 0) {
7686 use_visual_state (*visual_states[n]);
7690 Editor::start_visual_state_op (uint32_t n)
7692 save_visual_state (n);
7694 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7696 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7697 pup->set_text (buf);
7702 Editor::cancel_visual_state_op (uint32_t n)
7704 goto_visual_state (n);
7708 Editor::toggle_region_mute ()
7710 if (_ignore_region_action) {
7714 RegionSelection rs = get_regions_from_selection_and_entered ();
7720 if (rs.size() > 1) {
7721 begin_reversible_command (_("mute regions"));
7723 begin_reversible_command (_("mute region"));
7726 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7728 (*i)->region()->playlist()->clear_changes ();
7729 (*i)->region()->set_muted (!(*i)->region()->muted ());
7730 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7734 commit_reversible_command ();
7738 Editor::combine_regions ()
7740 /* foreach track with selected regions, take all selected regions
7741 and join them into a new region containing the subregions (as a
7745 typedef set<RouteTimeAxisView*> RTVS;
7748 if (selection->regions.empty()) {
7752 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7753 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7756 tracks.insert (rtv);
7760 begin_reversible_command (_("combine regions"));
7762 vector<RegionView*> new_selection;
7764 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7767 if ((rv = (*i)->combine_regions ()) != 0) {
7768 new_selection.push_back (rv);
7772 selection->clear_regions ();
7773 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7774 selection->add (*i);
7777 commit_reversible_command ();
7781 Editor::uncombine_regions ()
7783 typedef set<RouteTimeAxisView*> RTVS;
7786 if (selection->regions.empty()) {
7790 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7791 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7794 tracks.insert (rtv);
7798 begin_reversible_command (_("uncombine regions"));
7800 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7801 (*i)->uncombine_regions ();
7804 commit_reversible_command ();
7808 Editor::toggle_midi_input_active (bool flip_others)
7811 boost::shared_ptr<RouteList> rl (new RouteList);
7813 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7814 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7820 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7823 rl->push_back (rtav->route());
7824 onoff = !mt->input_active();
7828 _session->set_exclusive_input_active (rl, onoff, flip_others);
7835 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7837 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7838 lock_dialog->get_vbox()->pack_start (*padlock);
7840 ArdourButton* b = manage (new ArdourButton);
7841 b->set_name ("lock button");
7842 b->set_text (_("Click to unlock"));
7843 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7844 lock_dialog->get_vbox()->pack_start (*b);
7846 lock_dialog->get_vbox()->show_all ();
7847 lock_dialog->set_size_request (200, 200);
7850 delete _main_menu_disabler;
7851 _main_menu_disabler = new MainMenuDisabler;
7853 lock_dialog->present ();
7859 lock_dialog->hide ();
7861 delete _main_menu_disabler;
7862 _main_menu_disabler = 0;
7864 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7865 start_lock_event_timing ();
7870 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7872 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7876 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7878 Timers::TimerSuspender t;
7879 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7880 Gtkmm2ext::UI::instance()->flush_pending ();
7884 Editor::bring_all_sources_into_session ()
7891 ArdourDialog w (_("Moving embedded files into session folder"));
7892 w.get_vbox()->pack_start (msg);
7895 /* flush all pending GUI events because we're about to start copying
7899 Timers::TimerSuspender t;
7900 Gtkmm2ext::UI::instance()->flush_pending ();
7904 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));