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());
1620 Editor::tav_zoom_step (bool coarser)
1622 DisplaySuspender ds;
1626 if (selection->tracks.empty()) {
1629 ts = &selection->tracks;
1632 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1633 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1634 tv->step_height (coarser);
1639 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1641 DisplaySuspender ds;
1645 if (selection->tracks.empty() || force_all) {
1648 ts = &selection->tracks;
1651 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1652 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1653 uint32_t h = tv->current_height ();
1658 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1663 tv->set_height (h + 5);
1670 Editor::temporal_zoom_step (bool coarser)
1672 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1674 framecnt_t nspp = samples_per_pixel;
1682 temporal_zoom (nspp);
1686 Editor::temporal_zoom (framecnt_t fpp)
1692 framepos_t current_page = current_page_samples();
1693 framepos_t current_leftmost = leftmost_frame;
1694 framepos_t current_rightmost;
1695 framepos_t current_center;
1696 framepos_t new_page_size;
1697 framepos_t half_page_size;
1698 framepos_t leftmost_after_zoom = 0;
1700 bool in_track_canvas;
1704 if (fpp == samples_per_pixel) {
1708 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1709 // segfaults for lack of memory. If somebody decides this is not high enough I
1710 // believe it can be raisen to higher values but some limit must be in place.
1712 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1713 // all of which is used for the editor track displays. The whole day
1714 // would be 4147200000 samples, so 2592000 samples per pixel.
1716 nfpp = min (fpp, (framecnt_t) 2592000);
1717 nfpp = max ((framecnt_t) 1, nfpp);
1719 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1720 half_page_size = new_page_size / 2;
1722 switch (zoom_focus) {
1724 leftmost_after_zoom = current_leftmost;
1727 case ZoomFocusRight:
1728 current_rightmost = leftmost_frame + current_page;
1729 if (current_rightmost < new_page_size) {
1730 leftmost_after_zoom = 0;
1732 leftmost_after_zoom = current_rightmost - new_page_size;
1736 case ZoomFocusCenter:
1737 current_center = current_leftmost + (current_page/2);
1738 if (current_center < half_page_size) {
1739 leftmost_after_zoom = 0;
1741 leftmost_after_zoom = current_center - half_page_size;
1745 case ZoomFocusPlayhead:
1746 /* centre playhead */
1747 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1750 leftmost_after_zoom = 0;
1751 } else if (l > max_framepos) {
1752 leftmost_after_zoom = max_framepos - new_page_size;
1754 leftmost_after_zoom = (framepos_t) l;
1758 case ZoomFocusMouse:
1759 /* try to keep the mouse over the same point in the display */
1761 if (!mouse_frame (where, in_track_canvas)) {
1762 /* use playhead instead */
1763 where = playhead_cursor->current_frame ();
1765 if (where < half_page_size) {
1766 leftmost_after_zoom = 0;
1768 leftmost_after_zoom = where - half_page_size;
1773 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1776 leftmost_after_zoom = 0;
1777 } else if (l > max_framepos) {
1778 leftmost_after_zoom = max_framepos - new_page_size;
1780 leftmost_after_zoom = (framepos_t) l;
1787 /* try to keep the edit point in the same place */
1788 where = get_preferred_edit_position ();
1792 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1795 leftmost_after_zoom = 0;
1796 } else if (l > max_framepos) {
1797 leftmost_after_zoom = max_framepos - new_page_size;
1799 leftmost_after_zoom = (framepos_t) l;
1803 /* edit point not defined */
1810 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1812 reposition_and_zoom (leftmost_after_zoom, nfpp);
1816 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1818 /* this func helps make sure we leave a little space
1819 at each end of the editor so that the zoom doesn't fit the region
1820 precisely to the screen.
1823 GdkScreen* screen = gdk_screen_get_default ();
1824 const gint pixwidth = gdk_screen_get_width (screen);
1825 const gint mmwidth = gdk_screen_get_width_mm (screen);
1826 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1827 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1829 const framepos_t range = end - start;
1830 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1831 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1833 if (start > extra_samples) {
1834 start -= extra_samples;
1839 if (max_framepos - extra_samples > end) {
1840 end += extra_samples;
1847 Editor::temporal_zoom_region (bool both_axes)
1849 framepos_t start = max_framepos;
1851 set<TimeAxisView*> tracks;
1853 if ( !get_selection_extents(start, end) )
1856 calc_extra_zoom_edges (start, end);
1858 /* if we're zooming on both axes we need to save track heights etc.
1861 undo_visual_stack.push_back (current_visual_state (both_axes));
1863 PBD::Unwinder<bool> nsv (no_save_visual, true);
1865 temporal_zoom_by_frame (start, end);
1868 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1870 /* set visible track heights appropriately */
1872 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1873 (*t)->set_height (per_track_height);
1876 /* hide irrelevant tracks */
1878 DisplaySuspender ds;
1880 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1881 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1882 hide_track_in_display (*i);
1886 vertical_adjustment.set_value (0.0);
1889 redo_visual_stack.push_back (current_visual_state (both_axes));
1894 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1896 start = max_framepos;
1900 //ToDo: if notes are selected, set extents to that selection
1902 //ToDo: if control points are selected, set extents to that selection
1904 if ( !selection->regions.empty() ) {
1905 RegionSelection rs = get_regions_from_selection_and_entered ();
1907 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1909 if ((*i)->region()->position() < start) {
1910 start = (*i)->region()->position();
1913 if ((*i)->region()->last_frame() + 1 > end) {
1914 end = (*i)->region()->last_frame() + 1;
1918 } else if (!selection->time.empty()) {
1919 start = selection->time.start();
1920 end = selection->time.end_frame();
1922 ret = false; //no selection found
1925 if ((start == 0 && end == 0) || end < start) {
1934 Editor::temporal_zoom_selection (bool both_axes)
1936 if (!selection) return;
1938 //ToDo: if notes are selected, zoom to that
1940 //ToDo: if control points are selected, zoom to that
1942 //if region(s) are selected, zoom to that
1943 if ( !selection->regions.empty() )
1944 temporal_zoom_region (both_axes);
1946 //if a range is selected, zoom to that
1947 if (!selection->time.empty()) {
1949 framepos_t start, end;
1950 if (get_selection_extents (start, end)) {
1951 calc_extra_zoom_edges(start, end);
1952 temporal_zoom_by_frame (start, end);
1962 Editor::temporal_zoom_session ()
1964 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1967 framecnt_t start = _session->current_start_frame();
1968 framecnt_t end = _session->current_end_frame();
1970 if (_session->actively_recording () ) {
1971 framepos_t cur = playhead_cursor->current_frame ();
1973 /* recording beyond the end marker; zoom out
1974 * by 5 seconds more so that if 'follow
1975 * playhead' is active we don't immediately
1978 end = cur + _session->frame_rate() * 5;
1982 if ((start == 0 && end == 0) || end < start) {
1986 calc_extra_zoom_edges(start, end);
1988 temporal_zoom_by_frame (start, end);
1993 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1995 if (!_session) return;
1997 if ((start == 0 && end == 0) || end < start) {
2001 framepos_t range = end - start;
2003 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2005 framepos_t new_page = range;
2006 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2007 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2009 if (new_leftmost > middle) {
2013 if (new_leftmost < 0) {
2017 reposition_and_zoom (new_leftmost, new_fpp);
2021 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2027 framecnt_t range_before = frame - leftmost_frame;
2031 if (samples_per_pixel <= 1) {
2034 new_spp = samples_per_pixel + (samples_per_pixel/2);
2036 range_before += range_before/2;
2038 if (samples_per_pixel >= 1) {
2039 new_spp = samples_per_pixel - (samples_per_pixel/2);
2041 /* could bail out here since we cannot zoom any finer,
2042 but leave that to the equality test below
2044 new_spp = samples_per_pixel;
2047 range_before -= range_before/2;
2050 if (new_spp == samples_per_pixel) {
2054 /* zoom focus is automatically taken as @param frame when this
2058 framepos_t new_leftmost = frame - (framepos_t)range_before;
2060 if (new_leftmost > frame) {
2064 if (new_leftmost < 0) {
2068 reposition_and_zoom (new_leftmost, new_spp);
2073 Editor::choose_new_marker_name(string &name) {
2075 if (!UIConfiguration::instance().get_name_new_markers()) {
2076 /* don't prompt user for a new name */
2080 ArdourPrompter dialog (true);
2082 dialog.set_prompt (_("New Name:"));
2084 dialog.set_title (_("New Location Marker"));
2086 dialog.set_name ("MarkNameWindow");
2087 dialog.set_size_request (250, -1);
2088 dialog.set_position (Gtk::WIN_POS_MOUSE);
2090 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2091 dialog.set_initial_text (name);
2095 switch (dialog.run ()) {
2096 case RESPONSE_ACCEPT:
2102 dialog.get_result(name);
2109 Editor::add_location_from_selection ()
2113 if (selection->time.empty()) {
2117 if (_session == 0 || clicked_axisview == 0) {
2121 framepos_t start = selection->time[clicked_selection].start;
2122 framepos_t end = selection->time[clicked_selection].end;
2124 _session->locations()->next_available_name(rangename,"selection");
2125 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2127 begin_reversible_command (_("add marker"));
2129 XMLNode &before = _session->locations()->get_state();
2130 _session->locations()->add (location, true);
2131 XMLNode &after = _session->locations()->get_state();
2132 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2134 commit_reversible_command ();
2138 Editor::add_location_mark (framepos_t where)
2142 select_new_marker = true;
2144 _session->locations()->next_available_name(markername,"mark");
2145 if (!choose_new_marker_name(markername)) {
2148 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
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::set_session_start_from_playhead ()
2166 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2167 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2169 XMLNode &before = loc->get_state();
2171 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2173 XMLNode &after = loc->get_state();
2175 begin_reversible_command (_("Set session start"));
2177 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2179 commit_reversible_command ();
2184 Editor::set_session_end_from_playhead ()
2190 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2191 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2193 XMLNode &before = loc->get_state();
2195 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2197 XMLNode &after = loc->get_state();
2199 begin_reversible_command (_("Set session start"));
2201 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2203 commit_reversible_command ();
2208 Editor::add_location_from_playhead_cursor ()
2210 add_location_mark (_session->audible_frame());
2214 Editor::remove_location_at_playhead_cursor ()
2218 XMLNode &before = _session->locations()->get_state();
2219 bool removed = false;
2221 //find location(s) at this time
2222 Locations::LocationList locs;
2223 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2224 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2225 if ((*i)->is_mark()) {
2226 _session->locations()->remove (*i);
2233 begin_reversible_command (_("remove marker"));
2234 XMLNode &after = _session->locations()->get_state();
2235 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2236 commit_reversible_command ();
2241 /** Add a range marker around each selected region */
2243 Editor::add_locations_from_region ()
2245 RegionSelection rs = get_regions_from_selection_and_entered ();
2250 bool commit = false;
2252 XMLNode &before = _session->locations()->get_state();
2254 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2256 boost::shared_ptr<Region> region = (*i)->region ();
2258 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2260 _session->locations()->add (location, true);
2265 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2266 XMLNode &after = _session->locations()->get_state();
2267 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2268 commit_reversible_command ();
2272 /** Add a single range marker around all selected regions */
2274 Editor::add_location_from_region ()
2276 RegionSelection rs = get_regions_from_selection_and_entered ();
2282 XMLNode &before = _session->locations()->get_state();
2286 if (rs.size() > 1) {
2287 _session->locations()->next_available_name(markername, "regions");
2289 RegionView* rv = *(rs.begin());
2290 boost::shared_ptr<Region> region = rv->region();
2291 markername = region->name();
2294 if (!choose_new_marker_name(markername)) {
2298 // single range spanning all selected
2299 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2300 _session->locations()->add (location, true);
2302 begin_reversible_command (_("add marker"));
2303 XMLNode &after = _session->locations()->get_state();
2304 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2305 commit_reversible_command ();
2311 Editor::jump_forward_to_mark ()
2317 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2323 _session->request_locate (pos, _session->transport_rolling());
2327 Editor::jump_backward_to_mark ()
2333 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2339 _session->request_locate (pos, _session->transport_rolling());
2345 framepos_t const pos = _session->audible_frame ();
2348 _session->locations()->next_available_name (markername, "mark");
2350 if (!choose_new_marker_name (markername)) {
2354 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2358 Editor::clear_markers ()
2361 begin_reversible_command (_("clear markers"));
2363 XMLNode &before = _session->locations()->get_state();
2364 _session->locations()->clear_markers ();
2365 XMLNode &after = _session->locations()->get_state();
2366 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2368 commit_reversible_command ();
2373 Editor::clear_ranges ()
2376 begin_reversible_command (_("clear ranges"));
2378 XMLNode &before = _session->locations()->get_state();
2380 _session->locations()->clear_ranges ();
2382 XMLNode &after = _session->locations()->get_state();
2383 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2385 commit_reversible_command ();
2390 Editor::clear_locations ()
2392 begin_reversible_command (_("clear locations"));
2394 XMLNode &before = _session->locations()->get_state();
2395 _session->locations()->clear ();
2396 XMLNode &after = _session->locations()->get_state();
2397 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2399 commit_reversible_command ();
2403 Editor::unhide_markers ()
2405 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2406 Location *l = (*i).first;
2407 if (l->is_hidden() && l->is_mark()) {
2408 l->set_hidden(false, this);
2414 Editor::unhide_ranges ()
2416 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2417 Location *l = (*i).first;
2418 if (l->is_hidden() && l->is_range_marker()) {
2419 l->set_hidden(false, this);
2424 /* INSERT/REPLACE */
2427 Editor::insert_region_list_selection (float times)
2429 RouteTimeAxisView *tv = 0;
2430 boost::shared_ptr<Playlist> playlist;
2432 if (clicked_routeview != 0) {
2433 tv = clicked_routeview;
2434 } else if (!selection->tracks.empty()) {
2435 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2438 } else if (entered_track != 0) {
2439 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2446 if ((playlist = tv->playlist()) == 0) {
2450 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2455 begin_reversible_command (_("insert region"));
2456 playlist->clear_changes ();
2457 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2458 if (Config->get_edit_mode() == Ripple)
2459 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2461 _session->add_command(new StatefulDiffCommand (playlist));
2462 commit_reversible_command ();
2465 /* BUILT-IN EFFECTS */
2468 Editor::reverse_selection ()
2473 /* GAIN ENVELOPE EDITING */
2476 Editor::edit_envelope ()
2483 Editor::transition_to_rolling (bool fwd)
2489 if (_session->config.get_external_sync()) {
2490 switch (Config->get_sync_source()) {
2494 /* transport controlled by the master */
2499 if (_session->is_auditioning()) {
2500 _session->cancel_audition ();
2504 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2508 Editor::play_from_start ()
2510 _session->request_locate (_session->current_start_frame(), true);
2514 Editor::play_from_edit_point ()
2516 _session->request_locate (get_preferred_edit_position(), true);
2520 Editor::play_from_edit_point_and_return ()
2522 framepos_t start_frame;
2523 framepos_t return_frame;
2525 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2527 if (_session->transport_rolling()) {
2528 _session->request_locate (start_frame, false);
2532 /* don't reset the return frame if its already set */
2534 if ((return_frame = _session->requested_return_frame()) < 0) {
2535 return_frame = _session->audible_frame();
2538 if (start_frame >= 0) {
2539 _session->request_roll_at_and_return (start_frame, return_frame);
2544 Editor::play_selection ()
2546 framepos_t start, end;
2547 if (!get_selection_extents ( start, end))
2550 AudioRange ar (start, end, 0);
2551 list<AudioRange> lar;
2554 _session->request_play_range (&lar, true);
2558 Editor::get_preroll ()
2560 return Config->get_preroll_seconds() * _session->frame_rate();
2565 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2567 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2570 location -= get_preroll();
2572 //don't try to locate before the beginning of time
2576 //if follow_playhead is on, keep the playhead on the screen
2577 if ( _follow_playhead )
2578 if ( location < leftmost_frame )
2579 location = leftmost_frame;
2581 _session->request_locate( location );
2585 Editor::play_with_preroll ()
2588 framepos_t preroll = get_preroll();
2590 framepos_t start, end;
2591 if (!get_selection_extents ( start, end))
2594 if (start > preroll)
2595 start = start - preroll;
2597 end = end + preroll; //"post-roll"
2599 AudioRange ar (start, end, 0);
2600 list<AudioRange> lar;
2603 _session->request_play_range (&lar, true);
2608 Editor::play_location (Location& location)
2610 if (location.start() <= location.end()) {
2614 _session->request_bounded_roll (location.start(), location.end());
2618 Editor::loop_location (Location& location)
2620 if (location.start() <= location.end()) {
2626 if ((tll = transport_loop_location()) != 0) {
2627 tll->set (location.start(), location.end());
2629 // enable looping, reposition and start rolling
2630 _session->request_locate (tll->start(), true);
2631 _session->request_play_loop (true);
2636 Editor::do_layer_operation (LayerOperation op)
2638 if (selection->regions.empty ()) {
2642 bool const multiple = selection->regions.size() > 1;
2646 begin_reversible_command (_("raise regions"));
2648 begin_reversible_command (_("raise region"));
2654 begin_reversible_command (_("raise regions to top"));
2656 begin_reversible_command (_("raise region to top"));
2662 begin_reversible_command (_("lower regions"));
2664 begin_reversible_command (_("lower region"));
2670 begin_reversible_command (_("lower regions to bottom"));
2672 begin_reversible_command (_("lower region"));
2677 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2678 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2679 (*i)->clear_owned_changes ();
2682 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2683 boost::shared_ptr<Region> r = (*i)->region ();
2695 r->lower_to_bottom ();
2699 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2700 vector<Command*> cmds;
2702 _session->add_commands (cmds);
2705 commit_reversible_command ();
2709 Editor::raise_region ()
2711 do_layer_operation (Raise);
2715 Editor::raise_region_to_top ()
2717 do_layer_operation (RaiseToTop);
2721 Editor::lower_region ()
2723 do_layer_operation (Lower);
2727 Editor::lower_region_to_bottom ()
2729 do_layer_operation (LowerToBottom);
2732 /** Show the region editor for the selected regions */
2734 Editor::show_region_properties ()
2736 selection->foreach_regionview (&RegionView::show_region_editor);
2739 /** Show the midi list editor for the selected MIDI regions */
2741 Editor::show_midi_list_editor ()
2743 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2747 Editor::rename_region ()
2749 RegionSelection rs = get_regions_from_selection_and_entered ();
2755 ArdourDialog d (*this, _("Rename Region"), true, false);
2757 Label label (_("New name:"));
2760 hbox.set_spacing (6);
2761 hbox.pack_start (label, false, false);
2762 hbox.pack_start (entry, true, true);
2764 d.get_vbox()->set_border_width (12);
2765 d.get_vbox()->pack_start (hbox, false, false);
2767 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2768 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2770 d.set_size_request (300, -1);
2772 entry.set_text (rs.front()->region()->name());
2773 entry.select_region (0, -1);
2775 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2781 int const ret = d.run();
2785 if (ret != RESPONSE_OK) {
2789 std::string str = entry.get_text();
2790 strip_whitespace_edges (str);
2792 rs.front()->region()->set_name (str);
2793 _regions->redisplay ();
2797 /** Start an audition of the first selected region */
2799 Editor::play_edit_range ()
2801 framepos_t start, end;
2803 if (get_edit_op_range (start, end)) {
2804 _session->request_bounded_roll (start, end);
2809 Editor::play_selected_region ()
2811 framepos_t start = max_framepos;
2814 RegionSelection rs = get_regions_from_selection_and_entered ();
2820 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2821 if ((*i)->region()->position() < start) {
2822 start = (*i)->region()->position();
2824 if ((*i)->region()->last_frame() + 1 > end) {
2825 end = (*i)->region()->last_frame() + 1;
2829 _session->request_bounded_roll (start, end);
2833 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2835 _session->audition_region (region);
2839 Editor::region_from_selection ()
2841 if (clicked_axisview == 0) {
2845 if (selection->time.empty()) {
2849 framepos_t start = selection->time[clicked_selection].start;
2850 framepos_t end = selection->time[clicked_selection].end;
2852 TrackViewList tracks = get_tracks_for_range_action ();
2854 framepos_t selection_cnt = end - start + 1;
2856 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2857 boost::shared_ptr<Region> current;
2858 boost::shared_ptr<Playlist> pl;
2859 framepos_t internal_start;
2862 if ((pl = (*i)->playlist()) == 0) {
2866 if ((current = pl->top_region_at (start)) == 0) {
2870 internal_start = start - current->position();
2871 RegionFactory::region_name (new_name, current->name(), true);
2875 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2876 plist.add (ARDOUR::Properties::length, selection_cnt);
2877 plist.add (ARDOUR::Properties::name, new_name);
2878 plist.add (ARDOUR::Properties::layer, 0);
2880 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2885 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2887 if (selection->time.empty() || selection->tracks.empty()) {
2891 framepos_t start, end;
2892 if (clicked_selection) {
2893 start = selection->time[clicked_selection].start;
2894 end = selection->time[clicked_selection].end;
2896 start = selection->time.start();
2897 end = selection->time.end_frame();
2900 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2901 sort_track_selection (ts);
2903 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2904 boost::shared_ptr<Region> current;
2905 boost::shared_ptr<Playlist> playlist;
2906 framepos_t internal_start;
2909 if ((playlist = (*i)->playlist()) == 0) {
2913 if ((current = playlist->top_region_at(start)) == 0) {
2917 internal_start = start - current->position();
2918 RegionFactory::region_name (new_name, current->name(), true);
2922 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2923 plist.add (ARDOUR::Properties::length, end - start + 1);
2924 plist.add (ARDOUR::Properties::name, new_name);
2926 new_regions.push_back (RegionFactory::create (current, plist));
2931 Editor::split_multichannel_region ()
2933 RegionSelection rs = get_regions_from_selection_and_entered ();
2939 vector< boost::shared_ptr<Region> > v;
2941 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2942 (*x)->region()->separate_by_channel (*_session, v);
2947 Editor::new_region_from_selection ()
2949 region_from_selection ();
2950 cancel_selection ();
2954 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2956 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2957 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2958 case Evoral::OverlapNone:
2966 * - selected tracks, or if there are none...
2967 * - tracks containing selected regions, or if there are none...
2972 Editor::get_tracks_for_range_action () const
2976 if (selection->tracks.empty()) {
2978 /* use tracks with selected regions */
2980 RegionSelection rs = selection->regions;
2982 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2983 TimeAxisView* tv = &(*i)->get_time_axis_view();
2985 if (!t.contains (tv)) {
2991 /* no regions and no tracks: use all tracks */
2997 t = selection->tracks;
3000 return t.filter_to_unique_playlists();
3004 Editor::separate_regions_between (const TimeSelection& ts)
3006 bool in_command = false;
3007 boost::shared_ptr<Playlist> playlist;
3008 RegionSelection new_selection;
3010 TrackViewList tmptracks = get_tracks_for_range_action ();
3011 sort_track_selection (tmptracks);
3013 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3015 RouteTimeAxisView* rtv;
3017 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3019 if (rtv->is_track()) {
3021 /* no edits to destructive tracks */
3023 if (rtv->track()->destructive()) {
3027 if ((playlist = rtv->playlist()) != 0) {
3029 playlist->clear_changes ();
3031 /* XXX need to consider musical time selections here at some point */
3033 double speed = rtv->track()->speed();
3036 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3038 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3039 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3041 latest_regionviews.clear ();
3043 playlist->partition ((framepos_t)((*t).start * speed),
3044 (framepos_t)((*t).end * speed), false);
3048 if (!latest_regionviews.empty()) {
3050 rtv->view()->foreach_regionview (sigc::bind (
3051 sigc::ptr_fun (add_if_covered),
3052 &(*t), &new_selection));
3055 begin_reversible_command (_("separate"));
3059 /* pick up changes to existing regions */
3061 vector<Command*> cmds;
3062 playlist->rdiff (cmds);
3063 _session->add_commands (cmds);
3065 /* pick up changes to the playlist itself (adds/removes)
3068 _session->add_command(new StatefulDiffCommand (playlist));
3077 // selection->set (new_selection);
3079 commit_reversible_command ();
3083 struct PlaylistState {
3084 boost::shared_ptr<Playlist> playlist;
3088 /** Take tracks from get_tracks_for_range_action and cut any regions
3089 * on those tracks so that the tracks are empty over the time
3093 Editor::separate_region_from_selection ()
3095 /* preferentially use *all* ranges in the time selection if we're in range mode
3096 to allow discontiguous operation, since get_edit_op_range() currently
3097 returns a single range.
3100 if (!selection->time.empty()) {
3102 separate_regions_between (selection->time);
3109 if (get_edit_op_range (start, end)) {
3111 AudioRange ar (start, end, 1);
3115 separate_regions_between (ts);
3121 Editor::separate_region_from_punch ()
3123 Location* loc = _session->locations()->auto_punch_location();
3125 separate_regions_using_location (*loc);
3130 Editor::separate_region_from_loop ()
3132 Location* loc = _session->locations()->auto_loop_location();
3134 separate_regions_using_location (*loc);
3139 Editor::separate_regions_using_location (Location& loc)
3141 if (loc.is_mark()) {
3145 AudioRange ar (loc.start(), loc.end(), 1);
3150 separate_regions_between (ts);
3153 /** Separate regions under the selected region */
3155 Editor::separate_under_selected_regions ()
3157 vector<PlaylistState> playlists;
3161 rs = get_regions_from_selection_and_entered();
3163 if (!_session || rs.empty()) {
3167 begin_reversible_command (_("separate region under"));
3169 list<boost::shared_ptr<Region> > regions_to_remove;
3171 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3172 // we can't just remove the region(s) in this loop because
3173 // this removes them from the RegionSelection, and they thus
3174 // disappear from underneath the iterator, and the ++i above
3175 // SEGVs in a puzzling fashion.
3177 // so, first iterate over the regions to be removed from rs and
3178 // add them to the regions_to_remove list, and then
3179 // iterate over the list to actually remove them.
3181 regions_to_remove.push_back ((*i)->region());
3184 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3186 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3189 // is this check necessary?
3193 vector<PlaylistState>::iterator i;
3195 //only take state if this is a new playlist.
3196 for (i = playlists.begin(); i != playlists.end(); ++i) {
3197 if ((*i).playlist == playlist) {
3202 if (i == playlists.end()) {
3204 PlaylistState before;
3205 before.playlist = playlist;
3206 before.before = &playlist->get_state();
3208 playlist->freeze ();
3209 playlists.push_back(before);
3212 //Partition on the region bounds
3213 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3215 //Re-add region that was just removed due to the partition operation
3216 playlist->add_region( (*rl), (*rl)->first_frame() );
3219 vector<PlaylistState>::iterator pl;
3221 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3222 (*pl).playlist->thaw ();
3223 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3226 commit_reversible_command ();
3230 Editor::crop_region_to_selection ()
3232 if (!selection->time.empty()) {
3234 crop_region_to (selection->time.start(), selection->time.end_frame());
3241 if (get_edit_op_range (start, end)) {
3242 crop_region_to (start, end);
3249 Editor::crop_region_to (framepos_t start, framepos_t end)
3251 vector<boost::shared_ptr<Playlist> > playlists;
3252 boost::shared_ptr<Playlist> playlist;
3255 if (selection->tracks.empty()) {
3256 ts = track_views.filter_to_unique_playlists();
3258 ts = selection->tracks.filter_to_unique_playlists ();
3261 sort_track_selection (ts);
3263 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3265 RouteTimeAxisView* rtv;
3267 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3269 boost::shared_ptr<Track> t = rtv->track();
3271 if (t != 0 && ! t->destructive()) {
3273 if ((playlist = rtv->playlist()) != 0) {
3274 playlists.push_back (playlist);
3280 if (playlists.empty()) {
3285 framepos_t new_start;
3287 framecnt_t new_length;
3288 bool in_command = false;
3290 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3292 /* Only the top regions at start and end have to be cropped */
3293 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3294 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3296 vector<boost::shared_ptr<Region> > regions;
3298 if (region_at_start != 0) {
3299 regions.push_back (region_at_start);
3301 if (region_at_end != 0) {
3302 regions.push_back (region_at_end);
3305 /* now adjust lengths */
3306 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3308 pos = (*i)->position();
3309 new_start = max (start, pos);
3310 if (max_framepos - pos > (*i)->length()) {
3311 new_end = pos + (*i)->length() - 1;
3313 new_end = max_framepos;
3315 new_end = min (end, new_end);
3316 new_length = new_end - new_start + 1;
3319 begin_reversible_command (_("trim to selection"));
3322 (*i)->clear_changes ();
3323 (*i)->trim_to (new_start, new_length);
3324 _session->add_command (new StatefulDiffCommand (*i));
3329 commit_reversible_command ();
3334 Editor::region_fill_track ()
3336 boost::shared_ptr<Playlist> playlist;
3337 RegionSelection regions = get_regions_from_selection_and_entered ();
3338 RegionSelection foo;
3340 framepos_t const end = _session->current_end_frame ();
3342 if (regions.empty () || regions.end_frame () + 1 >= end) {
3346 framepos_t const start_frame = regions.start ();
3347 framepos_t const end_frame = regions.end_frame ();
3348 framecnt_t const gap = end_frame - start_frame + 1;
3350 begin_reversible_command (Operations::region_fill);
3352 selection->clear_regions ();
3354 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3356 boost::shared_ptr<Region> r ((*i)->region());
3358 TimeAxisView& tv = (*i)->get_time_axis_view();
3359 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3360 latest_regionviews.clear ();
3361 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3363 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3364 playlist = (*i)->region()->playlist();
3365 playlist->clear_changes ();
3366 playlist->duplicate_until (r, position, gap, end);
3367 _session->add_command(new StatefulDiffCommand (playlist));
3371 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3375 selection->set (foo);
3378 commit_reversible_command ();
3382 Editor::set_region_sync_position ()
3384 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3388 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3390 bool in_command = false;
3392 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3394 if (!(*r)->region()->covers (where)) {
3398 boost::shared_ptr<Region> region ((*r)->region());
3401 begin_reversible_command (_("set sync point"));
3405 region->clear_changes ();
3406 region->set_sync_position (where);
3407 _session->add_command(new StatefulDiffCommand (region));
3411 commit_reversible_command ();
3415 /** Remove the sync positions of the selection */
3417 Editor::remove_region_sync ()
3419 RegionSelection rs = get_regions_from_selection_and_entered ();
3425 begin_reversible_command (_("remove region sync"));
3427 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3429 (*i)->region()->clear_changes ();
3430 (*i)->region()->clear_sync_position ();
3431 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3434 commit_reversible_command ();
3438 Editor::naturalize_region ()
3440 RegionSelection rs = get_regions_from_selection_and_entered ();
3446 if (rs.size() > 1) {
3447 begin_reversible_command (_("move regions to original position"));
3449 begin_reversible_command (_("move region to original position"));
3452 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3453 (*i)->region()->clear_changes ();
3454 (*i)->region()->move_to_natural_position ();
3455 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3458 commit_reversible_command ();
3462 Editor::align_regions (RegionPoint what)
3464 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3470 begin_reversible_command (_("align selection"));
3472 framepos_t const position = get_preferred_edit_position ();
3474 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3475 align_region_internal ((*i)->region(), what, position);
3478 commit_reversible_command ();
3481 struct RegionSortByTime {
3482 bool operator() (const RegionView* a, const RegionView* b) {
3483 return a->region()->position() < b->region()->position();
3488 Editor::align_regions_relative (RegionPoint point)
3490 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3496 framepos_t const position = get_preferred_edit_position ();
3498 framepos_t distance = 0;
3502 list<RegionView*> sorted;
3503 rs.by_position (sorted);
3505 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3510 if (position > r->position()) {
3511 distance = position - r->position();
3513 distance = r->position() - position;
3519 if (position > r->last_frame()) {
3520 distance = position - r->last_frame();
3521 pos = r->position() + distance;
3523 distance = r->last_frame() - position;
3524 pos = r->position() - distance;
3530 pos = r->adjust_to_sync (position);
3531 if (pos > r->position()) {
3532 distance = pos - r->position();
3534 distance = r->position() - pos;
3540 if (pos == r->position()) {
3544 begin_reversible_command (_("align selection (relative)"));
3546 /* move first one specially */
3548 r->clear_changes ();
3549 r->set_position (pos);
3550 _session->add_command(new StatefulDiffCommand (r));
3552 /* move rest by the same amount */
3556 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3558 boost::shared_ptr<Region> region ((*i)->region());
3560 region->clear_changes ();
3563 region->set_position (region->position() + distance);
3565 region->set_position (region->position() - distance);
3568 _session->add_command(new StatefulDiffCommand (region));
3572 commit_reversible_command ();
3576 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3578 begin_reversible_command (_("align region"));
3579 align_region_internal (region, point, position);
3580 commit_reversible_command ();
3584 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3586 region->clear_changes ();
3590 region->set_position (region->adjust_to_sync (position));
3594 if (position > region->length()) {
3595 region->set_position (position - region->length());
3600 region->set_position (position);
3604 _session->add_command(new StatefulDiffCommand (region));
3608 Editor::trim_region_front ()
3614 Editor::trim_region_back ()
3616 trim_region (false);
3620 Editor::trim_region (bool front)
3622 framepos_t where = get_preferred_edit_position();
3623 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3629 begin_reversible_command (front ? _("trim front") : _("trim back"));
3631 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3632 if (!(*i)->region()->locked()) {
3634 (*i)->region()->clear_changes ();
3637 (*i)->region()->trim_front (where);
3638 maybe_locate_with_edit_preroll ( where );
3640 (*i)->region()->trim_end (where);
3641 maybe_locate_with_edit_preroll ( where );
3644 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3648 commit_reversible_command ();
3651 /** Trim the end of the selected regions to the position of the edit cursor */
3653 Editor::trim_region_to_loop ()
3655 Location* loc = _session->locations()->auto_loop_location();
3659 trim_region_to_location (*loc, _("trim to loop"));
3663 Editor::trim_region_to_punch ()
3665 Location* loc = _session->locations()->auto_punch_location();
3669 trim_region_to_location (*loc, _("trim to punch"));
3673 Editor::trim_region_to_location (const Location& loc, const char* str)
3675 RegionSelection rs = get_regions_from_selection_and_entered ();
3676 bool in_command = false;
3678 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3679 RegionView* rv = (*x);
3681 /* require region to span proposed trim */
3682 switch (rv->region()->coverage (loc.start(), loc.end())) {
3683 case Evoral::OverlapInternal:
3689 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3698 if (tav->track() != 0) {
3699 speed = tav->track()->speed();
3702 start = session_frame_to_track_frame (loc.start(), speed);
3703 end = session_frame_to_track_frame (loc.end(), speed);
3705 rv->region()->clear_changes ();
3706 rv->region()->trim_to (start, (end - start));
3709 begin_reversible_command (str);
3712 _session->add_command(new StatefulDiffCommand (rv->region()));
3716 commit_reversible_command ();
3721 Editor::trim_region_to_previous_region_end ()
3723 return trim_to_region(false);
3727 Editor::trim_region_to_next_region_start ()
3729 return trim_to_region(true);
3733 Editor::trim_to_region(bool forward)
3735 RegionSelection rs = get_regions_from_selection_and_entered ();
3736 bool in_command = false;
3738 boost::shared_ptr<Region> next_region;
3740 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3742 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3748 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3756 if (atav->track() != 0) {
3757 speed = atav->track()->speed();
3761 boost::shared_ptr<Region> region = arv->region();
3762 boost::shared_ptr<Playlist> playlist (region->playlist());
3764 region->clear_changes ();
3768 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3774 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3775 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3779 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3785 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3787 arv->region_changed (ARDOUR::bounds_change);
3791 begin_reversible_command (_("trim to region"));
3794 _session->add_command(new StatefulDiffCommand (region));
3798 commit_reversible_command ();
3803 Editor::unfreeze_route ()
3805 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3809 clicked_routeview->track()->unfreeze ();
3813 Editor::_freeze_thread (void* arg)
3815 return static_cast<Editor*>(arg)->freeze_thread ();
3819 Editor::freeze_thread ()
3821 /* create event pool because we may need to talk to the session */
3822 SessionEvent::create_per_thread_pool ("freeze events", 64);
3823 /* create per-thread buffers for process() tree to use */
3824 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3825 current_interthread_info->done = true;
3830 Editor::freeze_route ()
3836 /* stop transport before we start. this is important */
3838 _session->request_transport_speed (0.0);
3840 /* wait for just a little while, because the above call is asynchronous */
3842 Glib::usleep (250000);
3844 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3848 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3850 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3851 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3853 d.set_title (_("Cannot freeze"));
3858 if (clicked_routeview->track()->has_external_redirects()) {
3859 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"
3860 "Freezing will only process the signal as far as the first send/insert/return."),
3861 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3863 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3864 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3865 d.set_title (_("Freeze Limits"));
3867 int response = d.run ();
3870 case Gtk::RESPONSE_CANCEL:
3877 InterThreadInfo itt;
3878 current_interthread_info = &itt;
3880 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3882 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3884 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3886 while (!itt.done && !itt.cancel) {
3887 gtk_main_iteration ();
3890 current_interthread_info = 0;
3894 Editor::bounce_range_selection (bool replace, bool enable_processing)
3896 if (selection->time.empty()) {
3900 TrackSelection views = selection->tracks;
3902 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3904 if (enable_processing) {
3906 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3908 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3910 _("You can't perform this operation because the processing of the signal "
3911 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3912 "You can do this without processing, which is a different operation.")
3914 d.set_title (_("Cannot bounce"));
3921 framepos_t start = selection->time[clicked_selection].start;
3922 framepos_t end = selection->time[clicked_selection].end;
3923 framepos_t cnt = end - start + 1;
3924 bool in_command = false;
3926 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3928 RouteTimeAxisView* rtv;
3930 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3934 boost::shared_ptr<Playlist> playlist;
3936 if ((playlist = rtv->playlist()) == 0) {
3940 InterThreadInfo itt;
3942 playlist->clear_changes ();
3943 playlist->clear_owned_changes ();
3945 boost::shared_ptr<Region> r;
3947 if (enable_processing) {
3948 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3950 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3958 list<AudioRange> ranges;
3959 ranges.push_back (AudioRange (start, start+cnt, 0));
3960 playlist->cut (ranges); // discard result
3961 playlist->add_region (r, start);
3965 begin_reversible_command (_("bounce range"));
3968 vector<Command*> cmds;
3969 playlist->rdiff (cmds);
3970 _session->add_commands (cmds);
3972 _session->add_command (new StatefulDiffCommand (playlist));
3976 commit_reversible_command ();
3980 /** Delete selected regions, automation points or a time range */
3984 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3985 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3986 bool deleted = false;
3987 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3988 deleted = current_mixer_strip->delete_processors ();
3994 /** Cut selected regions, automation points or a time range */
4001 /** Copy selected regions, automation points or a time range */
4009 /** @return true if a Cut, Copy or Clear is possible */
4011 Editor::can_cut_copy () const
4013 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4020 /** Cut, copy or clear selected regions, automation points or a time range.
4021 * @param op Operation (Delete, Cut, Copy or Clear)
4024 Editor::cut_copy (CutCopyOp op)
4026 /* only cancel selection if cut/copy is successful.*/
4032 opname = _("delete");
4041 opname = _("clear");
4045 /* if we're deleting something, and the mouse is still pressed,
4046 the thing we started a drag for will be gone when we release
4047 the mouse button(s). avoid this. see part 2 at the end of
4051 if (op == Delete || op == Cut || op == Clear) {
4052 if (_drags->active ()) {
4057 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4058 cut_buffer->clear ();
4060 if (entered_marker) {
4062 /* cut/delete op while pointing at a marker */
4065 Location* loc = find_location_from_marker (entered_marker, ignored);
4067 if (_session && loc) {
4068 entered_marker = NULL;
4069 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4076 switch (mouse_mode) {
4079 begin_reversible_command (opname + ' ' + X_("MIDI"));
4081 commit_reversible_command ();
4087 bool did_edit = false;
4089 if (!selection->regions.empty() || !selection->points.empty()) {
4090 begin_reversible_command (opname + ' ' + _("objects"));
4093 if (!selection->regions.empty()) {
4094 cut_copy_regions (op, selection->regions);
4096 if (op == Cut || op == Delete) {
4097 selection->clear_regions ();
4101 if (!selection->points.empty()) {
4102 cut_copy_points (op);
4104 if (op == Cut || op == Delete) {
4105 selection->clear_points ();
4108 } else if (selection->time.empty()) {
4109 framepos_t start, end;
4110 /* no time selection, see if we can get an edit range
4113 if (get_edit_op_range (start, end)) {
4114 selection->set (start, end);
4116 } else if (!selection->time.empty()) {
4117 begin_reversible_command (opname + ' ' + _("range"));
4120 cut_copy_ranges (op);
4122 if (op == Cut || op == Delete) {
4123 selection->clear_time ();
4128 /* reset repeated paste state */
4131 commit_reversible_command ();
4134 if (op == Delete || op == Cut || op == Clear) {
4139 struct AutomationRecord {
4140 AutomationRecord () : state (0) , line(NULL) {}
4141 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4143 XMLNode* state; ///< state before any operation
4144 const AutomationLine* line; ///< line this came from
4145 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4148 /** Cut, copy or clear selected automation points.
4149 * @param op Operation (Cut, Copy or Clear)
4152 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4154 if (selection->points.empty ()) {
4158 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4159 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4161 /* Keep a record of the AutomationLists that we end up using in this operation */
4162 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4165 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4166 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4167 const AutomationLine& line = (*i)->line();
4168 const boost::shared_ptr<AutomationList> al = line.the_list();
4169 if (lists.find (al) == lists.end ()) {
4170 /* We haven't seen this list yet, so make a record for it. This includes
4171 taking a copy of its current state, in case this is needed for undo later.
4173 lists[al] = AutomationRecord (&al->get_state (), &line);
4177 if (op == Cut || op == Copy) {
4178 /* This operation will involve putting things in the cut buffer, so create an empty
4179 ControlList for each of our source lists to put the cut buffer data in.
4181 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4182 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4185 /* Add all selected points to the relevant copy ControlLists */
4186 framepos_t start = std::numeric_limits<framepos_t>::max();
4187 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4188 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4189 AutomationList::const_iterator j = (*i)->model();
4191 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4193 /* Update earliest MIDI start time in beats */
4194 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4196 /* Update earliest session start time in frames */
4197 start = std::min(start, (*i)->line().session_position(j));
4201 /* Snap start time backwards, so copy/paste is snap aligned. */
4203 if (earliest == Evoral::Beats::max()) {
4204 earliest = Evoral::Beats(); // Weird... don't offset
4206 earliest.round_down_to_beat();
4208 if (start == std::numeric_limits<double>::max()) {
4209 start = 0; // Weird... don't offset
4211 snap_to(start, RoundDownMaybe);
4214 const double line_offset = midi ? earliest.to_double() : start;
4215 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4216 /* Correct this copy list so that it is relative to the earliest
4217 start time, so relative ordering between points is preserved
4218 when copying from several lists and the paste starts at the
4219 earliest copied piece of data. */
4220 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4221 (*j)->when -= line_offset;
4224 /* And add it to the cut buffer */
4225 cut_buffer->add (i->second.copy);
4229 if (op == Delete || op == Cut) {
4230 /* This operation needs to remove things from the main AutomationList, so do that now */
4232 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4233 i->first->freeze ();
4236 /* Remove each selected point from its AutomationList */
4237 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4238 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4239 al->erase ((*i)->model ());
4242 /* Thaw the lists and add undo records for them */
4243 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4244 boost::shared_ptr<AutomationList> al = i->first;
4246 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4251 /** Cut, copy or clear selected automation points.
4252 * @param op Operation (Cut, Copy or Clear)
4255 Editor::cut_copy_midi (CutCopyOp op)
4257 Evoral::Beats earliest = Evoral::Beats::max();
4258 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4259 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4261 if (!mrv->selection().empty()) {
4262 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4264 mrv->cut_copy_clear (op);
4266 /* XXX: not ideal, as there may be more than one track involved in the selection */
4267 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4271 if (!selection->points.empty()) {
4272 cut_copy_points (op, earliest, true);
4273 if (op == Cut || op == Delete) {
4274 selection->clear_points ();
4279 struct lt_playlist {
4280 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4281 return a.playlist < b.playlist;
4285 struct PlaylistMapping {
4287 boost::shared_ptr<Playlist> pl;
4289 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4292 /** Remove `clicked_regionview' */
4294 Editor::remove_clicked_region ()
4296 if (clicked_routeview == 0 || clicked_regionview == 0) {
4300 begin_reversible_command (_("remove region"));
4302 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4304 playlist->clear_changes ();
4305 playlist->clear_owned_changes ();
4306 playlist->remove_region (clicked_regionview->region());
4307 if (Config->get_edit_mode() == Ripple)
4308 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4310 /* We might have removed regions, which alters other regions' layering_index,
4311 so we need to do a recursive diff here.
4313 vector<Command*> cmds;
4314 playlist->rdiff (cmds);
4315 _session->add_commands (cmds);
4317 _session->add_command(new StatefulDiffCommand (playlist));
4318 commit_reversible_command ();
4322 /** Remove the selected regions */
4324 Editor::remove_selected_regions ()
4326 RegionSelection rs = get_regions_from_selection_and_entered ();
4328 if (!_session || rs.empty()) {
4332 list<boost::shared_ptr<Region> > regions_to_remove;
4334 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4335 // we can't just remove the region(s) in this loop because
4336 // this removes them from the RegionSelection, and they thus
4337 // disappear from underneath the iterator, and the ++i above
4338 // SEGVs in a puzzling fashion.
4340 // so, first iterate over the regions to be removed from rs and
4341 // add them to the regions_to_remove list, and then
4342 // iterate over the list to actually remove them.
4344 regions_to_remove.push_back ((*i)->region());
4347 vector<boost::shared_ptr<Playlist> > playlists;
4349 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4351 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4354 // is this check necessary?
4358 /* get_regions_from_selection_and_entered() guarantees that
4359 the playlists involved are unique, so there is no need
4363 playlists.push_back (playlist);
4365 playlist->clear_changes ();
4366 playlist->clear_owned_changes ();
4367 playlist->freeze ();
4368 playlist->remove_region (*rl);
4369 if (Config->get_edit_mode() == Ripple)
4370 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4374 vector<boost::shared_ptr<Playlist> >::iterator pl;
4375 bool in_command = false;
4377 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4380 /* We might have removed regions, which alters other regions' layering_index,
4381 so we need to do a recursive diff here.
4385 begin_reversible_command (_("remove region"));
4388 vector<Command*> cmds;
4389 (*pl)->rdiff (cmds);
4390 _session->add_commands (cmds);
4392 _session->add_command(new StatefulDiffCommand (*pl));
4396 commit_reversible_command ();
4400 /** Cut, copy or clear selected regions.
4401 * @param op Operation (Cut, Copy or Clear)
4404 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4406 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4407 a map when we want ordered access to both elements. i think.
4410 vector<PlaylistMapping> pmap;
4412 framepos_t first_position = max_framepos;
4414 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4415 FreezeList freezelist;
4417 /* get ordering correct before we cut/copy */
4419 rs.sort_by_position_and_track ();
4421 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4423 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4425 if (op == Cut || op == Clear || op == Delete) {
4426 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4429 FreezeList::iterator fl;
4431 // only take state if this is a new playlist.
4432 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4438 if (fl == freezelist.end()) {
4439 pl->clear_changes();
4440 pl->clear_owned_changes ();
4442 freezelist.insert (pl);
4447 TimeAxisView* tv = &(*x)->get_time_axis_view();
4448 vector<PlaylistMapping>::iterator z;
4450 for (z = pmap.begin(); z != pmap.end(); ++z) {
4451 if ((*z).tv == tv) {
4456 if (z == pmap.end()) {
4457 pmap.push_back (PlaylistMapping (tv));
4461 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4463 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4466 /* region not yet associated with a playlist (e.g. unfinished
4473 TimeAxisView& tv = (*x)->get_time_axis_view();
4474 boost::shared_ptr<Playlist> npl;
4475 RegionSelection::iterator tmp;
4482 vector<PlaylistMapping>::iterator z;
4484 for (z = pmap.begin(); z != pmap.end(); ++z) {
4485 if ((*z).tv == &tv) {
4490 assert (z != pmap.end());
4493 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4501 boost::shared_ptr<Region> r = (*x)->region();
4502 boost::shared_ptr<Region> _xx;
4508 pl->remove_region (r);
4509 if (Config->get_edit_mode() == Ripple)
4510 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4514 _xx = RegionFactory::create (r);
4515 npl->add_region (_xx, r->position() - first_position);
4516 pl->remove_region (r);
4517 if (Config->get_edit_mode() == Ripple)
4518 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4522 /* copy region before adding, so we're not putting same object into two different playlists */
4523 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4527 pl->remove_region (r);
4528 if (Config->get_edit_mode() == Ripple)
4529 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4538 list<boost::shared_ptr<Playlist> > foo;
4540 /* the pmap is in the same order as the tracks in which selected regions occured */
4542 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4545 foo.push_back ((*i).pl);
4550 cut_buffer->set (foo);
4554 _last_cut_copy_source_track = 0;
4556 _last_cut_copy_source_track = pmap.front().tv;
4560 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4563 /* We might have removed regions, which alters other regions' layering_index,
4564 so we need to do a recursive diff here.
4566 vector<Command*> cmds;
4567 (*pl)->rdiff (cmds);
4568 _session->add_commands (cmds);
4570 _session->add_command (new StatefulDiffCommand (*pl));
4575 Editor::cut_copy_ranges (CutCopyOp op)
4577 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4579 /* Sort the track selection now, so that it if is used, the playlists
4580 selected by the calls below to cut_copy_clear are in the order that
4581 their tracks appear in the editor. This makes things like paste
4582 of ranges work properly.
4585 sort_track_selection (ts);
4588 if (!entered_track) {
4591 ts.push_back (entered_track);
4594 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4595 (*i)->cut_copy_clear (*selection, op);
4600 Editor::paste (float times, bool from_context)
4602 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4604 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4608 Editor::mouse_paste ()
4613 if (!mouse_frame (where, ignored)) {
4618 paste_internal (where, 1);
4622 Editor::paste_internal (framepos_t position, float times)
4624 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4626 if (cut_buffer->empty(internal_editing())) {
4630 if (position == max_framepos) {
4631 position = get_preferred_edit_position();
4632 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4635 if (position == last_paste_pos) {
4636 /* repeated paste in the same position */
4639 /* paste in new location, reset repeated paste state */
4641 last_paste_pos = position;
4644 /* get everything in the correct order */
4647 if (!selection->tracks.empty()) {
4648 /* If there is a track selection, paste into exactly those tracks and
4649 only those tracks. This allows the user to be explicit and override
4650 the below "do the reasonable thing" logic. */
4651 ts = selection->tracks.filter_to_unique_playlists ();
4652 sort_track_selection (ts);
4654 /* Figure out which track to base the paste at. */
4655 TimeAxisView* base_track = NULL;
4656 if (_edit_point == Editing::EditAtMouse && entered_track) {
4657 /* With the mouse edit point, paste onto the track under the mouse. */
4658 base_track = entered_track;
4659 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4660 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4661 base_track = &entered_regionview->get_time_axis_view();
4662 } else if (_last_cut_copy_source_track) {
4663 /* Paste to the track that the cut/copy came from (see mantis #333). */
4664 base_track = _last_cut_copy_source_track;
4666 /* This is "impossible" since we've copied... well, do nothing. */
4670 /* Walk up to parent if necessary, so base track is a route. */
4671 while (base_track->get_parent()) {
4672 base_track = base_track->get_parent();
4675 /* Add base track and all tracks below it. The paste logic will select
4676 the appropriate object types from the cut buffer in relative order. */
4677 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4678 if ((*i)->order() >= base_track->order()) {
4683 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4684 sort_track_selection (ts);
4686 /* Add automation children of each track in order, for pasting several lines. */
4687 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4688 /* Add any automation children for pasting several lines */
4689 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4694 typedef RouteTimeAxisView::AutomationTracks ATracks;
4695 const ATracks& atracks = rtv->automation_tracks();
4696 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4697 i = ts.insert(i, a->second.get());
4702 /* We now have a list of trackviews starting at base_track, including
4703 automation children, in the order shown in the editor, e.g. R1,
4704 R1.A1, R1.A2, R2, R2.A1, ... */
4707 begin_reversible_command (Operations::paste);
4709 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4710 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4711 /* Only one line copied, and one automation track selected. Do a
4712 "greedy" paste from one automation type to another. */
4714 PasteContext ctx(paste_count, times, ItemCounts(), true);
4715 ts.front()->paste (position, *cut_buffer, ctx);
4719 /* Paste into tracks */
4721 PasteContext ctx(paste_count, times, ItemCounts(), false);
4722 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4723 (*i)->paste (position, *cut_buffer, ctx);
4727 commit_reversible_command ();
4731 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4733 if (regions.empty ()) {
4737 boost::shared_ptr<Playlist> playlist;
4738 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4739 RegionSelection foo;
4741 framepos_t const start_frame = regions.start ();
4742 framepos_t const end_frame = regions.end_frame ();
4743 framecnt_t const gap = end_frame - start_frame + 1;
4745 begin_reversible_command (Operations::duplicate_region);
4747 selection->clear_regions ();
4749 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4751 boost::shared_ptr<Region> r ((*i)->region());
4753 TimeAxisView& tv = (*i)->get_time_axis_view();
4754 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4755 latest_regionviews.clear ();
4756 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4758 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4759 playlist = (*i)->region()->playlist();
4760 playlist->clear_changes ();
4761 playlist->duplicate (r, position, gap, times);
4762 _session->add_command(new StatefulDiffCommand (playlist));
4766 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4770 selection->set (foo);
4773 commit_reversible_command ();
4777 Editor::duplicate_selection (float times)
4779 if (selection->time.empty() || selection->tracks.empty()) {
4783 boost::shared_ptr<Playlist> playlist;
4784 vector<boost::shared_ptr<Region> > new_regions;
4785 vector<boost::shared_ptr<Region> >::iterator ri;
4787 create_region_from_selection (new_regions);
4789 if (new_regions.empty()) {
4793 ri = new_regions.begin();
4795 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4796 bool in_command = false;
4798 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4799 if ((playlist = (*i)->playlist()) == 0) {
4802 playlist->clear_changes ();
4804 if (clicked_selection) {
4805 end = selection->time[clicked_selection].end;
4807 end = selection->time.end_frame();
4809 playlist->duplicate (*ri, end + 1, times);
4812 begin_reversible_command (_("duplicate selection"));
4815 _session->add_command (new StatefulDiffCommand (playlist));
4818 if (ri == new_regions.end()) {
4824 commit_reversible_command ();
4828 /** Reset all selected points to the relevant default value */
4830 Editor::reset_point_selection ()
4832 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4833 ARDOUR::AutomationList::iterator j = (*i)->model ();
4834 (*j)->value = (*i)->line().the_list()->default_value ();
4839 Editor::center_playhead ()
4841 float const page = _visible_canvas_width * samples_per_pixel;
4842 center_screen_internal (playhead_cursor->current_frame (), page);
4846 Editor::center_edit_point ()
4848 float const page = _visible_canvas_width * samples_per_pixel;
4849 center_screen_internal (get_preferred_edit_position(), page);
4852 /** Caller must begin and commit a reversible command */
4854 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4856 playlist->clear_changes ();
4858 _session->add_command (new StatefulDiffCommand (playlist));
4862 Editor::nudge_track (bool use_edit, bool forwards)
4864 boost::shared_ptr<Playlist> playlist;
4865 framepos_t distance;
4866 framepos_t next_distance;
4870 start = get_preferred_edit_position();
4875 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4879 if (selection->tracks.empty()) {
4883 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4884 bool in_command = false;
4886 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4888 if ((playlist = (*i)->playlist()) == 0) {
4892 playlist->clear_changes ();
4893 playlist->clear_owned_changes ();
4895 playlist->nudge_after (start, distance, forwards);
4898 begin_reversible_command (_("nudge track"));
4901 vector<Command*> cmds;
4903 playlist->rdiff (cmds);
4904 _session->add_commands (cmds);
4906 _session->add_command (new StatefulDiffCommand (playlist));
4910 commit_reversible_command ();
4915 Editor::remove_last_capture ()
4917 vector<string> choices;
4924 if (Config->get_verify_remove_last_capture()) {
4925 prompt = _("Do you really want to destroy the last capture?"
4926 "\n(This is destructive and cannot be undone)");
4928 choices.push_back (_("No, do nothing."));
4929 choices.push_back (_("Yes, destroy it."));
4931 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4933 if (prompter.run () == 1) {
4934 _session->remove_last_capture ();
4935 _regions->redisplay ();
4939 _session->remove_last_capture();
4940 _regions->redisplay ();
4945 Editor::normalize_region ()
4951 RegionSelection rs = get_regions_from_selection_and_entered ();
4957 NormalizeDialog dialog (rs.size() > 1);
4959 if (dialog.run () == RESPONSE_CANCEL) {
4963 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4966 /* XXX: should really only count audio regions here */
4967 int const regions = rs.size ();
4969 /* Make a list of the selected audio regions' maximum amplitudes, and also
4970 obtain the maximum amplitude of them all.
4972 list<double> max_amps;
4974 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4975 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4977 dialog.descend (1.0 / regions);
4978 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4981 /* the user cancelled the operation */
4985 max_amps.push_back (a);
4986 max_amp = max (max_amp, a);
4991 list<double>::const_iterator a = max_amps.begin ();
4992 bool in_command = false;
4994 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4995 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5000 arv->region()->clear_changes ();
5002 double const amp = dialog.normalize_individually() ? *a : max_amp;
5004 arv->audio_region()->normalize (amp, dialog.target ());
5007 begin_reversible_command (_("normalize"));
5010 _session->add_command (new StatefulDiffCommand (arv->region()));
5016 commit_reversible_command ();
5022 Editor::reset_region_scale_amplitude ()
5028 RegionSelection rs = get_regions_from_selection_and_entered ();
5034 bool in_command = false;
5036 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5037 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5040 arv->region()->clear_changes ();
5041 arv->audio_region()->set_scale_amplitude (1.0f);
5044 begin_reversible_command ("reset gain");
5047 _session->add_command (new StatefulDiffCommand (arv->region()));
5051 commit_reversible_command ();
5056 Editor::adjust_region_gain (bool up)
5058 RegionSelection rs = get_regions_from_selection_and_entered ();
5060 if (!_session || rs.empty()) {
5064 bool in_command = false;
5066 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5067 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5072 arv->region()->clear_changes ();
5074 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5082 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5085 begin_reversible_command ("adjust region gain");
5088 _session->add_command (new StatefulDiffCommand (arv->region()));
5092 commit_reversible_command ();
5098 Editor::reverse_region ()
5104 Reverse rev (*_session);
5105 apply_filter (rev, _("reverse regions"));
5109 Editor::strip_region_silence ()
5115 RegionSelection rs = get_regions_from_selection_and_entered ();
5121 std::list<RegionView*> audio_only;
5123 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5124 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5126 audio_only.push_back (arv);
5130 assert (!audio_only.empty());
5132 StripSilenceDialog d (_session, audio_only);
5133 int const r = d.run ();
5137 if (r == Gtk::RESPONSE_OK) {
5138 ARDOUR::AudioIntervalMap silences;
5139 d.silences (silences);
5140 StripSilence s (*_session, silences, d.fade_length());
5141 apply_filter (s, _("strip silence"), &d);
5146 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5148 Evoral::Sequence<Evoral::Beats>::Notes selected;
5149 mrv.selection_as_notelist (selected, true);
5151 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5152 v.push_back (selected);
5154 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5155 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5157 return op (mrv.midi_region()->model(), pos_beats, v);
5161 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5167 bool in_command = false;
5169 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5170 RegionSelection::const_iterator tmp = r;
5173 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5176 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5179 begin_reversible_command (op.name ());
5183 _session->add_command (cmd);
5191 commit_reversible_command ();
5196 Editor::fork_region ()
5198 RegionSelection rs = get_regions_from_selection_and_entered ();
5204 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5205 bool in_command = false;
5209 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5210 RegionSelection::iterator tmp = r;
5213 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5217 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5218 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5219 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5222 begin_reversible_command (_("Fork Region(s)"));
5225 playlist->clear_changes ();
5226 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5227 _session->add_command(new StatefulDiffCommand (playlist));
5229 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5237 commit_reversible_command ();
5242 Editor::quantize_region ()
5245 quantize_regions(get_regions_from_selection_and_entered ());
5250 Editor::quantize_regions (const RegionSelection& rs)
5252 if (rs.n_midi_regions() == 0) {
5256 if (!quantize_dialog) {
5257 quantize_dialog = new QuantizeDialog (*this);
5260 quantize_dialog->present ();
5261 const int r = quantize_dialog->run ();
5262 quantize_dialog->hide ();
5264 if (r == Gtk::RESPONSE_OK) {
5265 Quantize quant (quantize_dialog->snap_start(),
5266 quantize_dialog->snap_end(),
5267 quantize_dialog->start_grid_size(),
5268 quantize_dialog->end_grid_size(),
5269 quantize_dialog->strength(),
5270 quantize_dialog->swing(),
5271 quantize_dialog->threshold());
5273 apply_midi_note_edit_op (quant, rs);
5278 Editor::legatize_region (bool shrink_only)
5281 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5286 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5288 if (rs.n_midi_regions() == 0) {
5292 Legatize legatize(shrink_only);
5293 apply_midi_note_edit_op (legatize, rs);
5297 Editor::transform_region ()
5300 transform_regions(get_regions_from_selection_and_entered ());
5305 Editor::transform_regions (const RegionSelection& rs)
5307 if (rs.n_midi_regions() == 0) {
5314 const int r = td.run();
5317 if (r == Gtk::RESPONSE_OK) {
5318 Transform transform(td.get());
5319 apply_midi_note_edit_op(transform, rs);
5324 Editor::transpose_region ()
5327 transpose_regions(get_regions_from_selection_and_entered ());
5332 Editor::transpose_regions (const RegionSelection& rs)
5334 if (rs.n_midi_regions() == 0) {
5339 int const r = d.run ();
5341 if (r == RESPONSE_ACCEPT) {
5342 Transpose transpose(d.semitones ());
5343 apply_midi_note_edit_op (transpose, rs);
5348 Editor::insert_patch_change (bool from_context)
5350 RegionSelection rs = get_regions_from_selection_and_entered ();
5356 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5358 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5359 there may be more than one, but the PatchChangeDialog can only offer
5360 one set of patch menus.
5362 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5364 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5365 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5367 if (d.run() == RESPONSE_CANCEL) {
5371 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5372 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5374 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5375 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5382 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5384 RegionSelection rs = get_regions_from_selection_and_entered ();
5390 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5391 bool in_command = false;
5396 int const N = rs.size ();
5398 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5399 RegionSelection::iterator tmp = r;
5402 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5404 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5407 progress->descend (1.0 / N);
5410 if (arv->audio_region()->apply (filter, progress) == 0) {
5412 playlist->clear_changes ();
5413 playlist->clear_owned_changes ();
5415 if (filter.results.empty ()) {
5417 /* no regions returned; remove the old one */
5418 playlist->remove_region (arv->region ());
5422 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5424 /* first region replaces the old one */
5425 playlist->replace_region (arv->region(), *res, (*res)->position());
5429 while (res != filter.results.end()) {
5430 playlist->add_region (*res, (*res)->position());
5435 /* We might have removed regions, which alters other regions' layering_index,
5436 so we need to do a recursive diff here.
5440 begin_reversible_command (command);
5443 vector<Command*> cmds;
5444 playlist->rdiff (cmds);
5445 _session->add_commands (cmds);
5447 _session->add_command(new StatefulDiffCommand (playlist));
5451 progress->ascend ();
5460 commit_reversible_command ();
5465 Editor::external_edit_region ()
5471 Editor::reset_region_gain_envelopes ()
5473 RegionSelection rs = get_regions_from_selection_and_entered ();
5475 if (!_session || rs.empty()) {
5479 bool in_command = false;
5481 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5482 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5484 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5485 XMLNode& before (alist->get_state());
5487 arv->audio_region()->set_default_envelope ();
5490 begin_reversible_command (_("reset region gain"));
5493 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5498 commit_reversible_command ();
5503 Editor::set_region_gain_visibility (RegionView* rv)
5505 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5507 arv->update_envelope_visibility();
5512 Editor::set_gain_envelope_visibility ()
5518 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5519 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5521 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5527 Editor::toggle_gain_envelope_active ()
5529 if (_ignore_region_action) {
5533 RegionSelection rs = get_regions_from_selection_and_entered ();
5535 if (!_session || rs.empty()) {
5539 bool in_command = false;
5541 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5542 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5544 arv->region()->clear_changes ();
5545 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5548 begin_reversible_command (_("region gain envelope active"));
5551 _session->add_command (new StatefulDiffCommand (arv->region()));
5556 commit_reversible_command ();
5561 Editor::toggle_region_lock ()
5563 if (_ignore_region_action) {
5567 RegionSelection rs = get_regions_from_selection_and_entered ();
5569 if (!_session || rs.empty()) {
5573 begin_reversible_command (_("toggle region lock"));
5575 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5576 (*i)->region()->clear_changes ();
5577 (*i)->region()->set_locked (!(*i)->region()->locked());
5578 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5581 commit_reversible_command ();
5585 Editor::toggle_region_video_lock ()
5587 if (_ignore_region_action) {
5591 RegionSelection rs = get_regions_from_selection_and_entered ();
5593 if (!_session || rs.empty()) {
5597 begin_reversible_command (_("Toggle Video Lock"));
5599 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5600 (*i)->region()->clear_changes ();
5601 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5602 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5605 commit_reversible_command ();
5609 Editor::toggle_region_lock_style ()
5611 if (_ignore_region_action) {
5615 RegionSelection rs = get_regions_from_selection_and_entered ();
5617 if (!_session || rs.empty()) {
5621 begin_reversible_command (_("region lock style"));
5623 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5624 (*i)->region()->clear_changes ();
5625 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5626 (*i)->region()->set_position_lock_style (ns);
5627 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5630 commit_reversible_command ();
5634 Editor::toggle_opaque_region ()
5636 if (_ignore_region_action) {
5640 RegionSelection rs = get_regions_from_selection_and_entered ();
5642 if (!_session || rs.empty()) {
5646 begin_reversible_command (_("change region opacity"));
5648 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5649 (*i)->region()->clear_changes ();
5650 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5651 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5654 commit_reversible_command ();
5658 Editor::toggle_record_enable ()
5660 bool new_state = false;
5662 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5663 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5666 if (!rtav->is_track())
5670 new_state = !rtav->track()->record_enabled();
5674 rtav->track()->set_record_enabled (new_state, this);
5679 Editor::toggle_solo ()
5681 bool new_state = false;
5683 boost::shared_ptr<RouteList> rl (new RouteList);
5685 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5686 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5693 new_state = !rtav->route()->soloed ();
5697 rl->push_back (rtav->route());
5700 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5704 Editor::toggle_mute ()
5706 bool new_state = false;
5708 boost::shared_ptr<RouteList> rl (new RouteList);
5710 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5711 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5718 new_state = !rtav->route()->muted();
5722 rl->push_back (rtav->route());
5725 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5729 Editor::toggle_solo_isolate ()
5735 Editor::fade_range ()
5737 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5739 begin_reversible_command (_("fade range"));
5741 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5742 (*i)->fade_range (selection->time);
5745 commit_reversible_command ();
5750 Editor::set_fade_length (bool in)
5752 RegionSelection rs = get_regions_from_selection_and_entered ();
5758 /* we need a region to measure the offset from the start */
5760 RegionView* rv = rs.front ();
5762 framepos_t pos = get_preferred_edit_position();
5766 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5767 /* edit point is outside the relevant region */
5772 if (pos <= rv->region()->position()) {
5776 len = pos - rv->region()->position();
5777 cmd = _("set fade in length");
5779 if (pos >= rv->region()->last_frame()) {
5783 len = rv->region()->last_frame() - pos;
5784 cmd = _("set fade out length");
5787 bool in_command = false;
5789 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5790 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5796 boost::shared_ptr<AutomationList> alist;
5798 alist = tmp->audio_region()->fade_in();
5800 alist = tmp->audio_region()->fade_out();
5803 XMLNode &before = alist->get_state();
5806 tmp->audio_region()->set_fade_in_length (len);
5807 tmp->audio_region()->set_fade_in_active (true);
5809 tmp->audio_region()->set_fade_out_length (len);
5810 tmp->audio_region()->set_fade_out_active (true);
5814 begin_reversible_command (cmd);
5817 XMLNode &after = alist->get_state();
5818 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5822 commit_reversible_command ();
5827 Editor::set_fade_in_shape (FadeShape shape)
5829 RegionSelection rs = get_regions_from_selection_and_entered ();
5834 bool in_command = false;
5836 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5837 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5843 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5844 XMLNode &before = alist->get_state();
5846 tmp->audio_region()->set_fade_in_shape (shape);
5849 begin_reversible_command (_("set fade in shape"));
5852 XMLNode &after = alist->get_state();
5853 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5857 commit_reversible_command ();
5862 Editor::set_fade_out_shape (FadeShape shape)
5864 RegionSelection rs = get_regions_from_selection_and_entered ();
5869 bool in_command = false;
5871 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5872 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5878 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5879 XMLNode &before = alist->get_state();
5881 tmp->audio_region()->set_fade_out_shape (shape);
5884 begin_reversible_command (_("set fade out shape"));
5887 XMLNode &after = alist->get_state();
5888 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5892 commit_reversible_command ();
5897 Editor::set_fade_in_active (bool yn)
5899 RegionSelection rs = get_regions_from_selection_and_entered ();
5904 bool in_command = false;
5906 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5907 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5914 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5916 ar->clear_changes ();
5917 ar->set_fade_in_active (yn);
5920 begin_reversible_command (_("set fade in active"));
5923 _session->add_command (new StatefulDiffCommand (ar));
5927 commit_reversible_command ();
5932 Editor::set_fade_out_active (bool yn)
5934 RegionSelection rs = get_regions_from_selection_and_entered ();
5939 bool in_command = false;
5941 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5942 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5948 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5950 ar->clear_changes ();
5951 ar->set_fade_out_active (yn);
5954 begin_reversible_command (_("set fade out active"));
5957 _session->add_command(new StatefulDiffCommand (ar));
5961 commit_reversible_command ();
5966 Editor::toggle_region_fades (int dir)
5968 if (_ignore_region_action) {
5972 boost::shared_ptr<AudioRegion> ar;
5975 RegionSelection rs = get_regions_from_selection_and_entered ();
5981 RegionSelection::iterator i;
5982 for (i = rs.begin(); i != rs.end(); ++i) {
5983 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5985 yn = ar->fade_out_active ();
5987 yn = ar->fade_in_active ();
5993 if (i == rs.end()) {
5997 /* XXX should this undo-able? */
5998 bool in_command = false;
6000 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6001 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6004 ar->clear_changes ();
6006 if (dir == 1 || dir == 0) {
6007 ar->set_fade_in_active (!yn);
6010 if (dir == -1 || dir == 0) {
6011 ar->set_fade_out_active (!yn);
6014 begin_reversible_command (_("toggle fade active"));
6017 _session->add_command(new StatefulDiffCommand (ar));
6021 commit_reversible_command ();
6026 /** Update region fade visibility after its configuration has been changed */
6028 Editor::update_region_fade_visibility ()
6030 bool _fade_visibility = _session->config.get_show_region_fades ();
6032 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6033 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6035 if (_fade_visibility) {
6036 v->audio_view()->show_all_fades ();
6038 v->audio_view()->hide_all_fades ();
6045 Editor::set_edit_point ()
6050 if (!mouse_frame (where, ignored)) {
6056 if (selection->markers.empty()) {
6058 mouse_add_new_marker (where);
6063 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6066 loc->move_to (where);
6072 Editor::set_playhead_cursor ()
6074 if (entered_marker) {
6075 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6080 if (!mouse_frame (where, ignored)) {
6087 _session->request_locate (where, _session->transport_rolling());
6091 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6092 cancel_time_selection();
6097 Editor::split_region ()
6099 if (_drags->active ()) {
6103 //if a range is selected, separate it
6104 if ( !selection->time.empty()) {
6105 separate_regions_between (selection->time);
6109 //if no range was selected, try to find some regions to split
6110 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6112 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6114 framepos_t where = get_preferred_edit_position ();
6120 split_regions_at (where, rs);
6124 struct EditorOrderRouteSorter {
6125 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6126 return a->order_key () < b->order_key ();
6131 Editor::select_next_route()
6133 if (selection->tracks.empty()) {
6134 selection->set (track_views.front());
6138 TimeAxisView* current = selection->tracks.front();
6142 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6143 if (*i == current) {
6145 if (i != track_views.end()) {
6148 current = (*(track_views.begin()));
6149 //selection->set (*(track_views.begin()));
6154 rui = dynamic_cast<RouteUI *>(current);
6155 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6157 selection->set(current);
6159 ensure_time_axis_view_is_visible (*current, false);
6163 Editor::select_prev_route()
6165 if (selection->tracks.empty()) {
6166 selection->set (track_views.front());
6170 TimeAxisView* current = selection->tracks.front();
6174 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6175 if (*i == current) {
6177 if (i != track_views.rend()) {
6180 current = *(track_views.rbegin());
6185 rui = dynamic_cast<RouteUI *>(current);
6186 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6188 selection->set (current);
6190 ensure_time_axis_view_is_visible (*current, false);
6194 Editor::set_loop_from_selection (bool play)
6196 if (_session == 0) {
6200 framepos_t start, end;
6201 if (!get_selection_extents ( start, end))
6204 set_loop_range (start, end, _("set loop range from selection"));
6207 _session->request_play_loop (true, true);
6212 Editor::set_loop_from_region (bool play)
6214 framepos_t start, end;
6215 if (!get_selection_extents ( start, end))
6218 set_loop_range (start, end, _("set loop range from region"));
6221 _session->request_locate (start, true);
6222 _session->request_play_loop (true);
6227 Editor::set_punch_from_selection ()
6229 if (_session == 0) {
6233 framepos_t start, end;
6234 if (!get_selection_extents ( start, end))
6237 set_punch_range (start, end, _("set punch range from selection"));
6241 Editor::set_session_extents_from_selection ()
6243 if (_session == 0) {
6247 framepos_t start, end;
6248 if (!get_selection_extents ( start, end))
6252 if ((loc = _session->locations()->session_range_location()) == 0) {
6253 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6255 XMLNode &before = loc->get_state();
6257 _session->set_session_extents ( start, end );
6259 XMLNode &after = loc->get_state();
6261 begin_reversible_command (_("set session start/end from selection"));
6263 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6265 commit_reversible_command ();
6270 Editor::set_punch_start_from_edit_point ()
6274 framepos_t start = 0;
6275 framepos_t end = max_framepos;
6277 //use the existing punch end, if any
6278 Location* tpl = transport_punch_location();
6283 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6284 start = _session->audible_frame();
6286 start = get_preferred_edit_position();
6289 //snap the selection start/end
6292 //if there's not already a sensible selection endpoint, go "forever"
6293 if ( start > end ) {
6297 set_punch_range (start, end, _("set punch start from EP"));
6303 Editor::set_punch_end_from_edit_point ()
6307 framepos_t start = 0;
6308 framepos_t end = max_framepos;
6310 //use the existing punch start, if any
6311 Location* tpl = transport_punch_location();
6313 start = tpl->start();
6316 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6317 end = _session->audible_frame();
6319 end = get_preferred_edit_position();
6322 //snap the selection start/end
6325 set_punch_range (start, end, _("set punch end from EP"));
6331 Editor::set_loop_start_from_edit_point ()
6335 framepos_t start = 0;
6336 framepos_t end = max_framepos;
6338 //use the existing loop end, if any
6339 Location* tpl = transport_loop_location();
6344 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6345 start = _session->audible_frame();
6347 start = get_preferred_edit_position();
6350 //snap the selection start/end
6353 //if there's not already a sensible selection endpoint, go "forever"
6354 if ( start > end ) {
6358 set_loop_range (start, end, _("set loop start from EP"));
6364 Editor::set_loop_end_from_edit_point ()
6368 framepos_t start = 0;
6369 framepos_t end = max_framepos;
6371 //use the existing loop start, if any
6372 Location* tpl = transport_loop_location();
6374 start = tpl->start();
6377 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6378 end = _session->audible_frame();
6380 end = get_preferred_edit_position();
6383 //snap the selection start/end
6386 set_loop_range (start, end, _("set loop end from EP"));
6391 Editor::set_punch_from_region ()
6393 framepos_t start, end;
6394 if (!get_selection_extents ( start, end))
6397 set_punch_range (start, end, _("set punch range from region"));
6401 Editor::pitch_shift_region ()
6403 RegionSelection rs = get_regions_from_selection_and_entered ();
6405 RegionSelection audio_rs;
6406 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6407 if (dynamic_cast<AudioRegionView*> (*i)) {
6408 audio_rs.push_back (*i);
6412 if (audio_rs.empty()) {
6416 pitch_shift (audio_rs, 1.2);
6420 Editor::set_tempo_from_region ()
6422 RegionSelection rs = get_regions_from_selection_and_entered ();
6424 if (!_session || rs.empty()) {
6428 RegionView* rv = rs.front();
6430 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6434 Editor::use_range_as_bar ()
6436 framepos_t start, end;
6437 if (get_edit_op_range (start, end)) {
6438 define_one_bar (start, end);
6443 Editor::define_one_bar (framepos_t start, framepos_t end)
6445 framepos_t length = end - start;
6447 const Meter& m (_session->tempo_map().meter_at (start));
6449 /* length = 1 bar */
6451 /* now we want frames per beat.
6452 we have frames per bar, and beats per bar, so ...
6455 /* XXXX METER MATH */
6457 double frames_per_beat = length / m.divisions_per_bar();
6459 /* beats per minute = */
6461 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6463 /* now decide whether to:
6465 (a) set global tempo
6466 (b) add a new tempo marker
6470 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6472 bool do_global = false;
6474 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6476 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6477 at the start, or create a new marker
6480 vector<string> options;
6481 options.push_back (_("Cancel"));
6482 options.push_back (_("Add new marker"));
6483 options.push_back (_("Set global tempo"));
6486 _("Define one bar"),
6487 _("Do you want to set the global tempo or add a new tempo marker?"),
6491 c.set_default_response (2);
6507 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6508 if the marker is at the region starter, change it, otherwise add
6513 begin_reversible_command (_("set tempo from region"));
6514 XMLNode& before (_session->tempo_map().get_state());
6517 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6518 } else if (t.frame() == start) {
6519 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6521 Timecode::BBT_Time bbt;
6522 _session->tempo_map().bbt_time (start, bbt);
6523 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6526 XMLNode& after (_session->tempo_map().get_state());
6528 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6529 commit_reversible_command ();
6533 Editor::split_region_at_transients ()
6535 AnalysisFeatureList positions;
6537 RegionSelection rs = get_regions_from_selection_and_entered ();
6539 if (!_session || rs.empty()) {
6543 begin_reversible_command (_("split regions"));
6545 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6547 RegionSelection::iterator tmp;
6552 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6554 if (ar && (ar->get_transients (positions) == 0)) {
6555 split_region_at_points ((*i)->region(), positions, true);
6562 commit_reversible_command ();
6567 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6569 bool use_rhythmic_rodent = false;
6571 boost::shared_ptr<Playlist> pl = r->playlist();
6573 list<boost::shared_ptr<Region> > new_regions;
6579 if (positions.empty()) {
6584 if (positions.size() > 20 && can_ferret) {
6585 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);
6586 MessageDialog msg (msgstr,
6589 Gtk::BUTTONS_OK_CANCEL);
6592 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6593 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6595 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6598 msg.set_title (_("Excessive split?"));
6601 int response = msg.run();
6607 case RESPONSE_APPLY:
6608 use_rhythmic_rodent = true;
6615 if (use_rhythmic_rodent) {
6616 show_rhythm_ferret ();
6620 AnalysisFeatureList::const_iterator x;
6622 pl->clear_changes ();
6623 pl->clear_owned_changes ();
6625 x = positions.begin();
6627 if (x == positions.end()) {
6632 pl->remove_region (r);
6636 while (x != positions.end()) {
6638 /* deal with positons that are out of scope of present region bounds */
6639 if (*x <= 0 || *x > r->length()) {
6644 /* file start = original start + how far we from the initial position ?
6647 framepos_t file_start = r->start() + pos;
6649 /* length = next position - current position
6652 framepos_t len = (*x) - pos;
6654 /* XXX we do we really want to allow even single-sample regions?
6655 shouldn't we have some kind of lower limit on region size?
6664 if (RegionFactory::region_name (new_name, r->name())) {
6668 /* do NOT announce new regions 1 by one, just wait till they are all done */
6672 plist.add (ARDOUR::Properties::start, file_start);
6673 plist.add (ARDOUR::Properties::length, len);
6674 plist.add (ARDOUR::Properties::name, new_name);
6675 plist.add (ARDOUR::Properties::layer, 0);
6677 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6678 /* because we set annouce to false, manually add the new region to the
6681 RegionFactory::map_add (nr);
6683 pl->add_region (nr, r->position() + pos);
6686 new_regions.push_front(nr);
6695 RegionFactory::region_name (new_name, r->name());
6697 /* Add the final region */
6700 plist.add (ARDOUR::Properties::start, r->start() + pos);
6701 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6702 plist.add (ARDOUR::Properties::name, new_name);
6703 plist.add (ARDOUR::Properties::layer, 0);
6705 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6706 /* because we set annouce to false, manually add the new region to the
6709 RegionFactory::map_add (nr);
6710 pl->add_region (nr, r->position() + pos);
6713 new_regions.push_front(nr);
6718 /* We might have removed regions, which alters other regions' layering_index,
6719 so we need to do a recursive diff here.
6721 vector<Command*> cmds;
6723 _session->add_commands (cmds);
6725 _session->add_command (new StatefulDiffCommand (pl));
6729 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6730 set_selected_regionview_from_region_list ((*i), Selection::Add);
6736 Editor::place_transient()
6742 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6748 framepos_t where = get_preferred_edit_position();
6750 begin_reversible_command (_("place transient"));
6752 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6753 framepos_t position = (*r)->region()->position();
6754 (*r)->region()->add_transient(where - position);
6757 commit_reversible_command ();
6761 Editor::remove_transient(ArdourCanvas::Item* item)
6767 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6770 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6771 _arv->remove_transient (*(float*) _line->get_data ("position"));
6775 Editor::snap_regions_to_grid ()
6777 list <boost::shared_ptr<Playlist > > used_playlists;
6779 RegionSelection rs = get_regions_from_selection_and_entered ();
6781 if (!_session || rs.empty()) {
6785 begin_reversible_command (_("snap regions to grid"));
6787 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6789 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6791 if (!pl->frozen()) {
6792 /* we haven't seen this playlist before */
6794 /* remember used playlists so we can thaw them later */
6795 used_playlists.push_back(pl);
6799 framepos_t start_frame = (*r)->region()->first_frame ();
6800 snap_to (start_frame);
6801 (*r)->region()->set_position (start_frame);
6804 while (used_playlists.size() > 0) {
6805 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6807 used_playlists.pop_front();
6810 commit_reversible_command ();
6814 Editor::close_region_gaps ()
6816 list <boost::shared_ptr<Playlist > > used_playlists;
6818 RegionSelection rs = get_regions_from_selection_and_entered ();
6820 if (!_session || rs.empty()) {
6824 Dialog dialog (_("Close Region Gaps"));
6827 table.set_spacings (12);
6828 table.set_border_width (12);
6829 Label* l = manage (left_aligned_label (_("Crossfade length")));
6830 table.attach (*l, 0, 1, 0, 1);
6832 SpinButton spin_crossfade (1, 0);
6833 spin_crossfade.set_range (0, 15);
6834 spin_crossfade.set_increments (1, 1);
6835 spin_crossfade.set_value (5);
6836 table.attach (spin_crossfade, 1, 2, 0, 1);
6838 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6840 l = manage (left_aligned_label (_("Pull-back length")));
6841 table.attach (*l, 0, 1, 1, 2);
6843 SpinButton spin_pullback (1, 0);
6844 spin_pullback.set_range (0, 100);
6845 spin_pullback.set_increments (1, 1);
6846 spin_pullback.set_value(30);
6847 table.attach (spin_pullback, 1, 2, 1, 2);
6849 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6851 dialog.get_vbox()->pack_start (table);
6852 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6853 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6856 if (dialog.run () == RESPONSE_CANCEL) {
6860 framepos_t crossfade_len = spin_crossfade.get_value();
6861 framepos_t pull_back_frames = spin_pullback.get_value();
6863 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6864 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6866 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6868 begin_reversible_command (_("close region gaps"));
6871 boost::shared_ptr<Region> last_region;
6873 rs.sort_by_position_and_track();
6875 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6877 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6879 if (!pl->frozen()) {
6880 /* we haven't seen this playlist before */
6882 /* remember used playlists so we can thaw them later */
6883 used_playlists.push_back(pl);
6887 framepos_t position = (*r)->region()->position();
6889 if (idx == 0 || position < last_region->position()){
6890 last_region = (*r)->region();
6895 (*r)->region()->trim_front( (position - pull_back_frames));
6896 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6898 last_region = (*r)->region();
6903 while (used_playlists.size() > 0) {
6904 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6906 used_playlists.pop_front();
6909 commit_reversible_command ();
6913 Editor::tab_to_transient (bool forward)
6915 AnalysisFeatureList positions;
6917 RegionSelection rs = get_regions_from_selection_and_entered ();
6923 framepos_t pos = _session->audible_frame ();
6925 if (!selection->tracks.empty()) {
6927 /* don't waste time searching for transients in duplicate playlists.
6930 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6932 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6934 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6937 boost::shared_ptr<Track> tr = rtv->track();
6939 boost::shared_ptr<Playlist> pl = tr->playlist ();
6941 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6944 positions.push_back (result);
6957 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6958 (*r)->region()->get_transients (positions);
6962 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6965 AnalysisFeatureList::iterator x;
6967 for (x = positions.begin(); x != positions.end(); ++x) {
6973 if (x != positions.end ()) {
6974 _session->request_locate (*x);
6978 AnalysisFeatureList::reverse_iterator x;
6980 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6986 if (x != positions.rend ()) {
6987 _session->request_locate (*x);
6993 Editor::playhead_forward_to_grid ()
6999 framepos_t pos = playhead_cursor->current_frame ();
7000 if (pos < max_framepos - 1) {
7002 snap_to_internal (pos, RoundUpAlways, false);
7003 _session->request_locate (pos);
7009 Editor::playhead_backward_to_grid ()
7015 framepos_t pos = playhead_cursor->current_frame ();
7018 snap_to_internal (pos, RoundDownAlways, false);
7019 _session->request_locate (pos);
7024 Editor::set_track_height (Height h)
7026 TrackSelection& ts (selection->tracks);
7028 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7029 (*x)->set_height_enum (h);
7034 Editor::toggle_tracks_active ()
7036 TrackSelection& ts (selection->tracks);
7038 bool target = false;
7044 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7045 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7049 target = !rtv->_route->active();
7052 rtv->_route->set_active (target, this);
7058 Editor::remove_tracks ()
7060 /* this will delete GUI objects that may be the subject of an event
7061 handler in which this method is called. Defer actual deletion to the
7062 next idle callback, when all event handling is finished.
7064 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7068 Editor::idle_remove_tracks ()
7071 return false; /* do not call again */
7075 Editor::_remove_tracks ()
7077 TrackSelection& ts (selection->tracks);
7083 vector<string> choices;
7087 const char* trackstr;
7089 vector<boost::shared_ptr<Route> > routes;
7090 bool special_bus = false;
7092 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7093 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7097 if (rtv->is_track()) {
7102 routes.push_back (rtv->_route);
7104 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7109 if (special_bus && !Config->get_allow_special_bus_removal()) {
7110 MessageDialog msg (_("That would be bad news ...."),
7114 msg.set_secondary_text (string_compose (_(
7115 "Removing the master or monitor bus is such a bad idea\n\
7116 that %1 is not going to allow it.\n\
7118 If you really want to do this sort of thing\n\
7119 edit your ardour.rc file to set the\n\
7120 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7127 if (ntracks + nbusses == 0) {
7131 trackstr = P_("track", "tracks", ntracks);
7132 busstr = P_("bus", "busses", nbusses);
7136 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7137 "(You may also lose the playlists associated with the %2)\n\n"
7138 "This action cannot be undone, and the session file will be overwritten!"),
7139 ntracks, trackstr, nbusses, busstr);
7141 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7142 "(You may also lose the playlists associated with the %2)\n\n"
7143 "This action cannot be undone, and the session file will be overwritten!"),
7146 } else if (nbusses) {
7147 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7148 "This action cannot be undone, and the session file will be overwritten"),
7152 choices.push_back (_("No, do nothing."));
7153 if (ntracks + nbusses > 1) {
7154 choices.push_back (_("Yes, remove them."));
7156 choices.push_back (_("Yes, remove it."));
7161 title = string_compose (_("Remove %1"), trackstr);
7163 title = string_compose (_("Remove %1"), busstr);
7166 Choice prompter (title, prompt, choices);
7168 if (prompter.run () != 1) {
7173 Session::StateProtector sp (_session);
7174 DisplaySuspender ds;
7175 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7176 _session->remove_route (*x);
7182 Editor::do_insert_time ()
7184 if (selection->tracks.empty()) {
7188 InsertRemoveTimeDialog d (*this);
7189 int response = d.run ();
7191 if (response != RESPONSE_OK) {
7195 if (d.distance() == 0) {
7199 InsertTimeOption opt = d.intersected_region_action ();
7202 get_preferred_edit_position(),
7208 d.move_glued_markers(),
7209 d.move_locked_markers(),
7215 Editor::insert_time (
7216 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7217 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7221 if (Config->get_edit_mode() == Lock) {
7224 bool in_command = false;
7226 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7228 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7232 /* don't operate on any playlist more than once, which could
7233 * happen if "all playlists" is enabled, but there is more
7234 * than 1 track using playlists "from" a given track.
7237 set<boost::shared_ptr<Playlist> > pl;
7239 if (all_playlists) {
7240 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7241 if (rtav && rtav->track ()) {
7242 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7243 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7248 if ((*x)->playlist ()) {
7249 pl.insert ((*x)->playlist ());
7253 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7255 (*i)->clear_changes ();
7256 (*i)->clear_owned_changes ();
7258 if (opt == SplitIntersected) {
7262 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7265 begin_reversible_command (_("insert time"));
7268 vector<Command*> cmds;
7270 _session->add_commands (cmds);
7272 _session->add_command (new StatefulDiffCommand (*i));
7276 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7279 begin_reversible_command (_("insert time"));
7282 rtav->route ()->shift (pos, frames);
7289 XMLNode& before (_session->locations()->get_state());
7290 Locations::LocationList copy (_session->locations()->list());
7292 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7294 Locations::LocationList::const_iterator tmp;
7296 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7297 bool const was_locked = (*i)->locked ();
7298 if (locked_markers_too) {
7302 if ((*i)->start() >= pos) {
7303 // move end first, in case we're moving by more than the length of the range
7304 if (!(*i)->is_mark()) {
7305 (*i)->set_end ((*i)->end() + frames);
7307 (*i)->set_start ((*i)->start() + frames);
7319 begin_reversible_command (_("insert time"));
7322 XMLNode& after (_session->locations()->get_state());
7323 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7329 begin_reversible_command (_("insert time"));
7332 XMLNode& before (_session->tempo_map().get_state());
7333 _session->tempo_map().insert_time (pos, frames);
7334 XMLNode& after (_session->tempo_map().get_state());
7335 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7339 commit_reversible_command ();
7344 Editor::do_remove_time ()
7346 if (selection->tracks.empty()) {
7350 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7351 InsertRemoveTimeDialog d (*this, true);
7353 int response = d.run ();
7355 if (response != RESPONSE_OK) {
7359 framecnt_t distance = d.distance();
7361 if (distance == 0) {
7371 d.move_glued_markers(),
7372 d.move_locked_markers(),
7378 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7379 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7381 if (Config->get_edit_mode() == Lock) {
7382 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7385 bool in_command = false;
7387 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7389 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7393 XMLNode &before = pl->get_state();
7395 std::list<AudioRange> rl;
7396 AudioRange ar(pos, pos+frames, 0);
7399 pl->shift (pos, -frames, true, ignore_music_glue);
7402 begin_reversible_command (_("cut time"));
7405 XMLNode &after = pl->get_state();
7407 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7411 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7414 begin_reversible_command (_("cut time"));
7417 rtav->route ()->shift (pos, -frames);
7421 std::list<Location*> loc_kill_list;
7426 XMLNode& before (_session->locations()->get_state());
7427 Locations::LocationList copy (_session->locations()->list());
7429 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7430 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7432 bool const was_locked = (*i)->locked ();
7433 if (locked_markers_too) {
7437 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7438 if ((*i)->end() >= pos
7439 && (*i)->end() < pos+frames
7440 && (*i)->start() >= pos
7441 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7443 loc_kill_list.push_back(*i);
7444 } else { // only start or end is included, try to do the right thing
7445 // move start before moving end, to avoid trying to move the end to before the start
7446 // if we're removing more time than the length of the range
7447 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7448 // start is within cut
7449 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7451 } else if ((*i)->start() >= pos+frames) {
7452 // start (and thus entire range) lies beyond end of cut
7453 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7456 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7457 // end is inside cut
7458 (*i)->set_end (pos); // bring the end to the cut
7460 } else if ((*i)->end() >= pos+frames) {
7461 // end is beyond end of cut
7462 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7467 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7468 loc_kill_list.push_back(*i);
7470 } else if ((*i)->start() >= pos) {
7471 (*i)->set_start ((*i)->start() -frames);
7481 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7482 _session->locations()->remove( *i );
7487 begin_reversible_command (_("cut time"));
7490 XMLNode& after (_session->locations()->get_state());
7491 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7496 XMLNode& before (_session->tempo_map().get_state());
7498 if (_session->tempo_map().remove_time (pos, frames) ) {
7500 begin_reversible_command (_("remove time"));
7503 XMLNode& after (_session->tempo_map().get_state());
7504 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7509 commit_reversible_command ();
7514 Editor::fit_selection ()
7516 if (!selection->tracks.empty()) {
7517 fit_tracks (selection->tracks);
7521 /* no selected tracks - use tracks with selected regions */
7523 if (!selection->regions.empty()) {
7524 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7525 tvl.push_back (&(*r)->get_time_axis_view ());
7531 } else if (internal_editing()) {
7532 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7535 if (entered_track) {
7536 tvl.push_back (entered_track);
7545 Editor::fit_tracks (TrackViewList & tracks)
7547 if (tracks.empty()) {
7551 uint32_t child_heights = 0;
7552 int visible_tracks = 0;
7554 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7556 if (!(*t)->marked_for_display()) {
7560 child_heights += (*t)->effective_height() - (*t)->current_height();
7564 /* compute the per-track height from:
7566 total canvas visible height -
7567 height that will be taken by visible children of selected
7568 tracks - height of the ruler/hscroll area
7570 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7571 double first_y_pos = DBL_MAX;
7573 if (h < TimeAxisView::preset_height (HeightSmall)) {
7574 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7575 /* too small to be displayed */
7579 undo_visual_stack.push_back (current_visual_state (true));
7580 PBD::Unwinder<bool> nsv (no_save_visual, true);
7582 /* build a list of all tracks, including children */
7585 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7587 TimeAxisView::Children c = (*i)->get_child_list ();
7588 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7589 all.push_back (j->get());
7594 // find selection range.
7595 // if someone knows how to user TrackViewList::iterator for this
7597 int selected_top = -1;
7598 int selected_bottom = -1;
7600 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7601 if ((*t)->marked_for_display ()) {
7602 if (tracks.contains(*t)) {
7603 if (selected_top == -1) {
7606 selected_bottom = i;
7612 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7613 if ((*t)->marked_for_display ()) {
7614 if (tracks.contains(*t)) {
7615 (*t)->set_height (h);
7616 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7618 if (i > selected_top && i < selected_bottom) {
7619 hide_track_in_display (*t);
7626 set the controls_layout height now, because waiting for its size
7627 request signal handler will cause the vertical adjustment setting to fail
7630 controls_layout.property_height () = _full_canvas_height;
7631 vertical_adjustment.set_value (first_y_pos);
7633 redo_visual_stack.push_back (current_visual_state (true));
7635 visible_tracks_selector.set_text (_("Sel"));
7639 Editor::save_visual_state (uint32_t n)
7641 while (visual_states.size() <= n) {
7642 visual_states.push_back (0);
7645 if (visual_states[n] != 0) {
7646 delete visual_states[n];
7649 visual_states[n] = current_visual_state (true);
7654 Editor::goto_visual_state (uint32_t n)
7656 if (visual_states.size() <= n) {
7660 if (visual_states[n] == 0) {
7664 use_visual_state (*visual_states[n]);
7668 Editor::start_visual_state_op (uint32_t n)
7670 save_visual_state (n);
7672 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7674 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7675 pup->set_text (buf);
7680 Editor::cancel_visual_state_op (uint32_t n)
7682 goto_visual_state (n);
7686 Editor::toggle_region_mute ()
7688 if (_ignore_region_action) {
7692 RegionSelection rs = get_regions_from_selection_and_entered ();
7698 if (rs.size() > 1) {
7699 begin_reversible_command (_("mute regions"));
7701 begin_reversible_command (_("mute region"));
7704 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7706 (*i)->region()->playlist()->clear_changes ();
7707 (*i)->region()->set_muted (!(*i)->region()->muted ());
7708 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7712 commit_reversible_command ();
7716 Editor::combine_regions ()
7718 /* foreach track with selected regions, take all selected regions
7719 and join them into a new region containing the subregions (as a
7723 typedef set<RouteTimeAxisView*> RTVS;
7726 if (selection->regions.empty()) {
7730 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7731 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7734 tracks.insert (rtv);
7738 begin_reversible_command (_("combine regions"));
7740 vector<RegionView*> new_selection;
7742 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7745 if ((rv = (*i)->combine_regions ()) != 0) {
7746 new_selection.push_back (rv);
7750 selection->clear_regions ();
7751 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7752 selection->add (*i);
7755 commit_reversible_command ();
7759 Editor::uncombine_regions ()
7761 typedef set<RouteTimeAxisView*> RTVS;
7764 if (selection->regions.empty()) {
7768 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7769 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7772 tracks.insert (rtv);
7776 begin_reversible_command (_("uncombine regions"));
7778 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7779 (*i)->uncombine_regions ();
7782 commit_reversible_command ();
7786 Editor::toggle_midi_input_active (bool flip_others)
7789 boost::shared_ptr<RouteList> rl (new RouteList);
7791 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7792 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7798 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7801 rl->push_back (rtav->route());
7802 onoff = !mt->input_active();
7806 _session->set_exclusive_input_active (rl, onoff, flip_others);
7813 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7815 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7816 lock_dialog->get_vbox()->pack_start (*padlock);
7818 ArdourButton* b = manage (new ArdourButton);
7819 b->set_name ("lock button");
7820 b->set_text (_("Click to unlock"));
7821 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7822 lock_dialog->get_vbox()->pack_start (*b);
7824 lock_dialog->get_vbox()->show_all ();
7825 lock_dialog->set_size_request (200, 200);
7828 delete _main_menu_disabler;
7829 _main_menu_disabler = new MainMenuDisabler;
7831 lock_dialog->present ();
7837 lock_dialog->hide ();
7839 delete _main_menu_disabler;
7840 _main_menu_disabler = 0;
7842 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7843 start_lock_event_timing ();
7848 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7850 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7854 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7856 Timers::TimerSuspender t;
7857 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7858 Gtkmm2ext::UI::instance()->flush_pending ();
7862 Editor::bring_all_sources_into_session ()
7869 ArdourDialog w (_("Moving embedded files into session folder"));
7870 w.get_vbox()->pack_start (msg);
7873 /* flush all pending GUI events because we're about to start copying
7877 Timers::TimerSuspender t;
7878 Gtkmm2ext::UI::instance()->flush_pending ();
7882 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));