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/boost_debug.h"
46 #include "ardour/dB.h"
47 #include "ardour/location.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/operations.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/profile.h"
53 #include "ardour/quantize.h"
54 #include "ardour/legatize.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/reverse.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/strip_silence.h"
60 #include "ardour/transient_detector.h"
61 #include "ardour/transpose.h"
63 #include "canvas/canvas.h"
66 #include "audio_region_view.h"
67 #include "audio_streamview.h"
68 #include "audio_time_axis.h"
69 #include "automation_region_view.h"
70 #include "automation_time_axis.h"
71 #include "control_point.h"
75 #include "editor_cursors.h"
76 #include "editor_drag.h"
77 #include "editor_regions.h"
78 #include "editor_routes.h"
79 #include "gui_thread.h"
80 #include "insert_remove_time_dialog.h"
81 #include "interthread_progress_window.h"
82 #include "item_counts.h"
84 #include "midi_region_view.h"
85 #include "mixer_strip.h"
86 #include "mouse_cursors.h"
87 #include "normalize_dialog.h"
89 #include "paste_context.h"
90 #include "patch_change_dialog.h"
91 #include "quantize_dialog.h"
92 #include "region_gain_line.h"
93 #include "rgb_macros.h"
94 #include "route_time_axis.h"
95 #include "selection.h"
96 #include "selection_templates.h"
97 #include "streamview.h"
98 #include "strip_silence_dialog.h"
99 #include "time_axis_view.h"
101 #include "transpose_dialog.h"
102 #include "transform_dialog.h"
103 #include "ui_config.h"
105 #include "pbd/i18n.h"
108 using namespace ARDOUR;
111 using namespace Gtkmm2ext;
112 using namespace Editing;
113 using Gtkmm2ext::Keyboard;
115 /***********************************************************************
117 ***********************************************************************/
120 Editor::undo (uint32_t n)
122 if (_drags->active ()) {
128 if (_session->undo_depth() == 0) {
129 undo_action->set_sensitive(false);
131 redo_action->set_sensitive(true);
132 begin_selection_op_history ();
137 Editor::redo (uint32_t n)
139 if (_drags->active ()) {
145 if (_session->redo_depth() == 0) {
146 redo_action->set_sensitive(false);
148 undo_action->set_sensitive(true);
149 begin_selection_op_history ();
154 Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int32_t sub_num)
158 RegionSelection pre_selected_regions = selection->regions;
159 bool working_on_selection = !pre_selected_regions.empty();
161 list<boost::shared_ptr<Playlist> > used_playlists;
162 list<RouteTimeAxisView*> used_trackviews;
164 if (regions.empty()) {
168 begin_reversible_command (_("split"));
170 // if splitting a single region, and snap-to is using
171 // region boundaries, don't pay attention to them
173 if (regions.size() == 1) {
174 switch (_snap_type) {
175 case SnapToRegionStart:
176 case SnapToRegionSync:
177 case SnapToRegionEnd:
186 EditorFreeze(); /* Emit Signal */
189 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
191 RegionSelection::iterator tmp;
193 /* XXX this test needs to be more complicated, to make sure we really
194 have something to split.
197 if (!(*a)->region()->covers (where)) {
205 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
213 /* we haven't seen this playlist before */
215 /* remember used playlists so we can thaw them later */
216 used_playlists.push_back(pl);
218 TimeAxisView& tv = (*a)->get_time_axis_view();
219 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
221 used_trackviews.push_back (rtv);
228 pl->clear_changes ();
229 pl->split_region ((*a)->region(), where, sub_num);
230 _session->add_command (new StatefulDiffCommand (pl));
236 latest_regionviews.clear ();
238 vector<sigc::connection> region_added_connections;
240 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
241 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
244 while (used_playlists.size() > 0) {
245 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
247 used_playlists.pop_front();
250 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
255 EditorThaw(); /* Emit Signal */
258 if (working_on_selection) {
259 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
261 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
262 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
263 /* There are three classes of regions that we might want selected after
264 splitting selected regions:
265 - regions selected before the split operation, and unaffected by it
266 - newly-created regions before the split
267 - newly-created regions after the split
270 if (rsas & Existing) {
271 // region selections that existed before the split.
272 selection->add ( pre_selected_regions );
275 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
276 if ((*ri)->region()->position() < where) {
277 // new regions created before the split
278 if (rsas & NewlyCreatedLeft) {
279 selection->add (*ri);
282 // new regions created after the split
283 if (rsas & NewlyCreatedRight) {
284 selection->add (*ri);
288 _ignore_follow_edits = false;
290 _ignore_follow_edits = true;
291 if( working_on_selection ) {
292 selection->add (latest_regionviews); //these are the new regions created after the split
294 _ignore_follow_edits = false;
297 commit_reversible_command ();
300 /** Move one extreme of the current range selection. If more than one range is selected,
301 * the start of the earliest range or the end of the latest range is moved.
303 * @param move_end true to move the end of the current range selection, false to move
305 * @param next true to move the extreme to the next region boundary, false to move to
309 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
311 if (selection->time.start() == selection->time.end_frame()) {
315 framepos_t start = selection->time.start ();
316 framepos_t end = selection->time.end_frame ();
318 /* the position of the thing we may move */
319 framepos_t pos = move_end ? end : start;
320 int dir = next ? 1 : -1;
322 /* so we don't find the current region again */
323 if (dir > 0 || pos > 0) {
327 framepos_t const target = get_region_boundary (pos, dir, true, false);
342 begin_reversible_selection_op (_("alter selection"));
343 selection->set_preserving_all_ranges (start, end);
344 commit_reversible_selection_op ();
348 Editor::nudge_forward_release (GdkEventButton* ev)
350 if (ev->state & Keyboard::PrimaryModifier) {
351 nudge_forward (false, true);
353 nudge_forward (false, false);
359 Editor::nudge_backward_release (GdkEventButton* ev)
361 if (ev->state & Keyboard::PrimaryModifier) {
362 nudge_backward (false, true);
364 nudge_backward (false, false);
371 Editor::nudge_forward (bool next, bool force_playhead)
374 framepos_t next_distance;
380 RegionSelection rs = get_regions_from_selection_and_entered ();
382 if (!force_playhead && !rs.empty()) {
384 begin_reversible_command (_("nudge regions forward"));
386 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
387 boost::shared_ptr<Region> r ((*i)->region());
389 distance = get_nudge_distance (r->position(), next_distance);
392 distance = next_distance;
396 r->set_position (r->position() + distance);
397 _session->add_command (new StatefulDiffCommand (r));
400 commit_reversible_command ();
403 } else if (!force_playhead && !selection->markers.empty()) {
406 bool in_command = false;
408 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
410 Location* loc = find_location_from_marker ((*i), is_start);
414 XMLNode& before (loc->get_state());
417 distance = get_nudge_distance (loc->start(), next_distance);
419 distance = next_distance;
421 if (max_framepos - distance > loc->start() + loc->length()) {
422 loc->set_start (loc->start() + distance);
424 loc->set_start (max_framepos - loc->length());
427 distance = get_nudge_distance (loc->end(), next_distance);
429 distance = next_distance;
431 if (max_framepos - distance > loc->end()) {
432 loc->set_end (loc->end() + distance);
434 loc->set_end (max_framepos);
436 if (loc->is_session_range()) {
437 _session->set_end_is_free (false);
441 begin_reversible_command (_("nudge location forward"));
444 XMLNode& after (loc->get_state());
445 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
450 commit_reversible_command ();
453 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
454 _session->request_locate (playhead_cursor->current_frame () + distance);
459 Editor::nudge_backward (bool next, bool force_playhead)
462 framepos_t next_distance;
468 RegionSelection rs = get_regions_from_selection_and_entered ();
470 if (!force_playhead && !rs.empty()) {
472 begin_reversible_command (_("nudge regions backward"));
474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
475 boost::shared_ptr<Region> r ((*i)->region());
477 distance = get_nudge_distance (r->position(), next_distance);
480 distance = next_distance;
485 if (r->position() > distance) {
486 r->set_position (r->position() - distance);
490 _session->add_command (new StatefulDiffCommand (r));
493 commit_reversible_command ();
495 } else if (!force_playhead && !selection->markers.empty()) {
498 bool in_command = false;
500 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
502 Location* loc = find_location_from_marker ((*i), is_start);
506 XMLNode& before (loc->get_state());
509 distance = get_nudge_distance (loc->start(), next_distance);
511 distance = next_distance;
513 if (distance < loc->start()) {
514 loc->set_start (loc->start() - distance);
519 distance = get_nudge_distance (loc->end(), next_distance);
522 distance = next_distance;
525 if (distance < loc->end() - loc->length()) {
526 loc->set_end (loc->end() - distance);
528 loc->set_end (loc->length());
530 if (loc->is_session_range()) {
531 _session->set_end_is_free (false);
535 begin_reversible_command (_("nudge location forward"));
538 XMLNode& after (loc->get_state());
539 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
543 commit_reversible_command ();
548 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
550 if (playhead_cursor->current_frame () > distance) {
551 _session->request_locate (playhead_cursor->current_frame () - distance);
553 _session->goto_start();
559 Editor::nudge_forward_capture_offset ()
561 RegionSelection rs = get_regions_from_selection_and_entered ();
563 if (!_session || rs.empty()) {
567 begin_reversible_command (_("nudge forward"));
569 framepos_t const distance = _session->worst_output_latency();
571 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
572 boost::shared_ptr<Region> r ((*i)->region());
575 r->set_position (r->position() + distance);
576 _session->add_command(new StatefulDiffCommand (r));
579 commit_reversible_command ();
583 Editor::nudge_backward_capture_offset ()
585 RegionSelection rs = get_regions_from_selection_and_entered ();
587 if (!_session || rs.empty()) {
591 begin_reversible_command (_("nudge backward"));
593 framepos_t const distance = _session->worst_output_latency();
595 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
596 boost::shared_ptr<Region> r ((*i)->region());
600 if (r->position() > distance) {
601 r->set_position (r->position() - distance);
605 _session->add_command(new StatefulDiffCommand (r));
608 commit_reversible_command ();
611 struct RegionSelectionPositionSorter {
612 bool operator() (RegionView* a, RegionView* b) {
613 return a->region()->position() < b->region()->position();
618 Editor::sequence_regions ()
621 framepos_t r_end_prev;
629 RegionSelection rs = get_regions_from_selection_and_entered ();
630 rs.sort(RegionSelectionPositionSorter());
634 bool in_command = false;
636 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
637 boost::shared_ptr<Region> r ((*i)->region());
645 if(r->position_locked())
652 r->set_position(r_end_prev);
656 begin_reversible_command (_("sequence regions"));
659 _session->add_command (new StatefulDiffCommand (r));
661 r_end=r->position() + r->length();
667 commit_reversible_command ();
676 Editor::move_to_start ()
678 _session->goto_start ();
682 Editor::move_to_end ()
685 _session->request_locate (_session->current_end_frame());
689 Editor::build_region_boundary_cache ()
692 vector<RegionPoint> interesting_points;
693 boost::shared_ptr<Region> r;
694 TrackViewList tracks;
697 region_boundary_cache.clear ();
703 switch (_snap_type) {
704 case SnapToRegionStart:
705 interesting_points.push_back (Start);
707 case SnapToRegionEnd:
708 interesting_points.push_back (End);
710 case SnapToRegionSync:
711 interesting_points.push_back (SyncPoint);
713 case SnapToRegionBoundary:
714 interesting_points.push_back (Start);
715 interesting_points.push_back (End);
718 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
719 abort(); /*NOTREACHED*/
723 TimeAxisView *ontrack = 0;
726 if (!selection->tracks.empty()) {
727 tlist = selection->tracks.filter_to_unique_playlists ();
729 tlist = track_views.filter_to_unique_playlists ();
732 while (pos < _session->current_end_frame() && !at_end) {
735 framepos_t lpos = max_framepos;
737 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
739 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
740 if (*p == interesting_points.back()) {
743 /* move to next point type */
749 rpos = r->first_frame();
753 rpos = r->last_frame();
757 rpos = r->sync_position ();
765 RouteTimeAxisView *rtav;
767 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
768 if (rtav->track() != 0) {
769 speed = rtav->track()->speed();
773 rpos = track_frame_to_session_frame (rpos, speed);
779 /* prevent duplicates, but we don't use set<> because we want to be able
783 vector<framepos_t>::iterator ri;
785 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
791 if (ri == region_boundary_cache.end()) {
792 region_boundary_cache.push_back (rpos);
799 /* finally sort to be sure that the order is correct */
801 sort (region_boundary_cache.begin(), region_boundary_cache.end());
804 boost::shared_ptr<Region>
805 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
807 TrackViewList::iterator i;
808 framepos_t closest = max_framepos;
809 boost::shared_ptr<Region> ret;
813 framepos_t track_frame;
814 RouteTimeAxisView *rtav;
816 for (i = tracks.begin(); i != tracks.end(); ++i) {
819 boost::shared_ptr<Region> r;
822 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
823 if (rtav->track()!=0)
824 track_speed = rtav->track()->speed();
827 track_frame = session_frame_to_track_frame(frame, track_speed);
829 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
835 rpos = r->first_frame ();
839 rpos = r->last_frame ();
843 rpos = r->sync_position ();
847 // rpos is a "track frame", converting it to "_session frame"
848 rpos = track_frame_to_session_frame(rpos, track_speed);
851 distance = rpos - frame;
853 distance = frame - rpos;
856 if (distance < closest) {
868 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
870 framecnt_t distance = max_framepos;
871 framepos_t current_nearest = -1;
873 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
874 framepos_t contender;
877 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
883 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
887 d = ::llabs (pos - contender);
890 current_nearest = contender;
895 return current_nearest;
899 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
904 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
906 if (!selection->tracks.empty()) {
908 target = find_next_region_boundary (pos, dir, selection->tracks);
912 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
913 get_onscreen_tracks (tvl);
914 target = find_next_region_boundary (pos, dir, tvl);
916 target = find_next_region_boundary (pos, dir, track_views);
922 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
923 get_onscreen_tracks (tvl);
924 target = find_next_region_boundary (pos, dir, tvl);
926 target = find_next_region_boundary (pos, dir, track_views);
934 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
936 framepos_t pos = playhead_cursor->current_frame ();
943 // so we don't find the current region again..
944 if (dir > 0 || pos > 0) {
948 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
952 _session->request_locate (target);
956 Editor::cursor_to_next_region_boundary (bool with_selection)
958 cursor_to_region_boundary (with_selection, 1);
962 Editor::cursor_to_previous_region_boundary (bool with_selection)
964 cursor_to_region_boundary (with_selection, -1);
968 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
970 boost::shared_ptr<Region> r;
971 framepos_t pos = cursor->current_frame ();
977 TimeAxisView *ontrack = 0;
979 // so we don't find the current region again..
983 if (!selection->tracks.empty()) {
985 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
987 } else if (clicked_axisview) {
990 t.push_back (clicked_axisview);
992 r = find_next_region (pos, point, dir, t, &ontrack);
996 r = find_next_region (pos, point, dir, track_views, &ontrack);
1005 pos = r->first_frame ();
1009 pos = r->last_frame ();
1013 pos = r->sync_position ();
1018 RouteTimeAxisView *rtav;
1020 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1021 if (rtav->track() != 0) {
1022 speed = rtav->track()->speed();
1026 pos = track_frame_to_session_frame(pos, speed);
1028 if (cursor == playhead_cursor) {
1029 _session->request_locate (pos);
1031 cursor->set_position (pos);
1036 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1038 cursor_to_region_point (cursor, point, 1);
1042 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1044 cursor_to_region_point (cursor, point, -1);
1048 Editor::cursor_to_selection_start (EditorCursor *cursor)
1052 switch (mouse_mode) {
1054 if (!selection->regions.empty()) {
1055 pos = selection->regions.start();
1060 if (!selection->time.empty()) {
1061 pos = selection->time.start ();
1069 if (cursor == playhead_cursor) {
1070 _session->request_locate (pos);
1072 cursor->set_position (pos);
1077 Editor::cursor_to_selection_end (EditorCursor *cursor)
1081 switch (mouse_mode) {
1083 if (!selection->regions.empty()) {
1084 pos = selection->regions.end_frame();
1089 if (!selection->time.empty()) {
1090 pos = selection->time.end_frame ();
1098 if (cursor == playhead_cursor) {
1099 _session->request_locate (pos);
1101 cursor->set_position (pos);
1106 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1116 if (selection->markers.empty()) {
1120 if (!mouse_frame (mouse, ignored)) {
1124 add_location_mark (mouse);
1127 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1131 framepos_t pos = loc->start();
1133 // so we don't find the current region again..
1134 if (dir > 0 || pos > 0) {
1138 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1142 loc->move_to (target);
1146 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1148 selected_marker_to_region_boundary (with_selection, 1);
1152 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1154 selected_marker_to_region_boundary (with_selection, -1);
1158 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1160 boost::shared_ptr<Region> r;
1165 if (!_session || selection->markers.empty()) {
1169 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1173 TimeAxisView *ontrack = 0;
1177 // so we don't find the current region again..
1181 if (!selection->tracks.empty()) {
1183 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1187 r = find_next_region (pos, point, dir, track_views, &ontrack);
1196 pos = r->first_frame ();
1200 pos = r->last_frame ();
1204 pos = r->adjust_to_sync (r->first_frame());
1209 RouteTimeAxisView *rtav;
1211 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1212 if (rtav->track() != 0) {
1213 speed = rtav->track()->speed();
1217 pos = track_frame_to_session_frame(pos, speed);
1223 Editor::selected_marker_to_next_region_point (RegionPoint point)
1225 selected_marker_to_region_point (point, 1);
1229 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1231 selected_marker_to_region_point (point, -1);
1235 Editor::selected_marker_to_selection_start ()
1241 if (!_session || selection->markers.empty()) {
1245 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1249 switch (mouse_mode) {
1251 if (!selection->regions.empty()) {
1252 pos = selection->regions.start();
1257 if (!selection->time.empty()) {
1258 pos = selection->time.start ();
1270 Editor::selected_marker_to_selection_end ()
1276 if (!_session || selection->markers.empty()) {
1280 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1284 switch (mouse_mode) {
1286 if (!selection->regions.empty()) {
1287 pos = selection->regions.end_frame();
1292 if (!selection->time.empty()) {
1293 pos = selection->time.end_frame ();
1305 Editor::scroll_playhead (bool forward)
1307 framepos_t pos = playhead_cursor->current_frame ();
1308 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1311 if (pos == max_framepos) {
1315 if (pos < max_framepos - delta) {
1334 _session->request_locate (pos);
1338 Editor::cursor_align (bool playhead_to_edit)
1344 if (playhead_to_edit) {
1346 if (selection->markers.empty()) {
1350 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1353 /* move selected markers to playhead */
1355 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1358 Location* loc = find_location_from_marker (*i, ignored);
1360 if (loc->is_mark()) {
1361 loc->set_start (playhead_cursor->current_frame ());
1363 loc->set (playhead_cursor->current_frame (),
1364 playhead_cursor->current_frame () + loc->length());
1371 Editor::scroll_backward (float pages)
1373 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1374 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1377 if (leftmost_frame < cnt) {
1380 frame = leftmost_frame - cnt;
1383 reset_x_origin (frame);
1387 Editor::scroll_forward (float pages)
1389 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1390 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1393 if (max_framepos - cnt < leftmost_frame) {
1394 frame = max_framepos - cnt;
1396 frame = leftmost_frame + cnt;
1399 reset_x_origin (frame);
1403 Editor::scroll_tracks_down ()
1405 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1406 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1407 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1410 vertical_adjustment.set_value (vert_value);
1414 Editor::scroll_tracks_up ()
1416 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1420 Editor::scroll_tracks_down_line ()
1422 double vert_value = vertical_adjustment.get_value() + 60;
1424 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1425 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1428 vertical_adjustment.set_value (vert_value);
1432 Editor::scroll_tracks_up_line ()
1434 reset_y_origin (vertical_adjustment.get_value() - 60);
1438 Editor::scroll_down_one_track (bool skip_child_views)
1440 TrackViewList::reverse_iterator next = track_views.rend();
1441 const double top_of_trackviews = vertical_adjustment.get_value();
1443 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1444 if ((*t)->hidden()) {
1448 /* If this is the upper-most visible trackview, we want to display
1449 * the one above it (next)
1451 * Note that covers_y_position() is recursive and includes child views
1453 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1456 if (skip_child_views) {
1459 /* automation lane (one level, non-recursive)
1461 * - if no automation lane exists -> move to next tack
1462 * - if the first (here: bottom-most) matches -> move to next tack
1463 * - if no y-axis match is found -> the current track is at the top
1464 * -> move to last (here: top-most) automation lane
1466 TimeAxisView::Children kids = (*t)->get_child_list();
1467 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1469 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1470 if ((*ci)->hidden()) {
1474 std::pair<TimeAxisView*,double> dev;
1475 dev = (*ci)->covers_y_position (top_of_trackviews);
1477 /* some automation lane is currently at the top */
1478 if (ci == kids.rbegin()) {
1479 /* first (bottom-most) autmation lane is at the top.
1480 * -> move to next track
1489 if (nkid != kids.rend()) {
1490 ensure_time_axis_view_is_visible (**nkid, true);
1498 /* move to the track below the first one that covers the */
1500 if (next != track_views.rend()) {
1501 ensure_time_axis_view_is_visible (**next, true);
1509 Editor::scroll_up_one_track (bool skip_child_views)
1511 TrackViewList::iterator prev = track_views.end();
1512 double top_of_trackviews = vertical_adjustment.get_value ();
1514 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1516 if ((*t)->hidden()) {
1520 /* find the trackview at the top of the trackview group
1522 * Note that covers_y_position() is recursive and includes child views
1524 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1527 if (skip_child_views) {
1530 /* automation lane (one level, non-recursive)
1532 * - if no automation lane exists -> move to prev tack
1533 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1534 * (actually last automation lane of previous track, see below)
1535 * - if first (top-most) lane is at the top -> move to this track
1536 * - else move up one lane
1538 TimeAxisView::Children kids = (*t)->get_child_list();
1539 TimeAxisView::Children::iterator pkid = kids.end();
1541 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1542 if ((*ci)->hidden()) {
1546 std::pair<TimeAxisView*,double> dev;
1547 dev = (*ci)->covers_y_position (top_of_trackviews);
1549 /* some automation lane is currently at the top */
1550 if (ci == kids.begin()) {
1551 /* first (top-most) autmation lane is at the top.
1552 * jump directly to this track's top
1554 ensure_time_axis_view_is_visible (**t, true);
1557 else if (pkid != kids.end()) {
1558 /* some other automation lane is at the top.
1559 * move up to prev automation lane.
1561 ensure_time_axis_view_is_visible (**pkid, true);
1564 assert(0); // not reached
1575 if (prev != track_views.end()) {
1576 // move to bottom-most automation-lane of the previous track
1577 TimeAxisView::Children kids = (*prev)->get_child_list();
1578 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1579 if (!skip_child_views) {
1580 // find the last visible lane
1581 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1582 if (!(*ci)->hidden()) {
1588 if (pkid != kids.rend()) {
1589 ensure_time_axis_view_is_visible (**pkid, true);
1591 ensure_time_axis_view_is_visible (**prev, true);
1600 Editor::scroll_left_step ()
1602 framepos_t xdelta = (current_page_samples() / 8);
1604 if (leftmost_frame > xdelta) {
1605 reset_x_origin (leftmost_frame - xdelta);
1613 Editor::scroll_right_step ()
1615 framepos_t xdelta = (current_page_samples() / 8);
1617 if (max_framepos - xdelta > leftmost_frame) {
1618 reset_x_origin (leftmost_frame + xdelta);
1620 reset_x_origin (max_framepos - current_page_samples());
1625 Editor::scroll_left_half_page ()
1627 framepos_t xdelta = (current_page_samples() / 2);
1628 if (leftmost_frame > xdelta) {
1629 reset_x_origin (leftmost_frame - xdelta);
1636 Editor::scroll_right_half_page ()
1638 framepos_t xdelta = (current_page_samples() / 2);
1639 if (max_framepos - xdelta > leftmost_frame) {
1640 reset_x_origin (leftmost_frame + xdelta);
1642 reset_x_origin (max_framepos - current_page_samples());
1649 Editor::tav_zoom_step (bool coarser)
1651 DisplaySuspender ds;
1655 if (selection->tracks.empty()) {
1658 ts = &selection->tracks;
1661 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1662 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1663 tv->step_height (coarser);
1668 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1670 DisplaySuspender ds;
1674 if (selection->tracks.empty() || force_all) {
1677 ts = &selection->tracks;
1680 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1681 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1682 uint32_t h = tv->current_height ();
1687 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1692 tv->set_height (h + 5);
1698 Editor::temporal_zoom_step_mouse_focus (bool coarser)
1700 Editing::ZoomFocus temp_focus = zoom_focus;
1701 zoom_focus = Editing::ZoomFocusMouse;
1702 temporal_zoom_step (coarser);
1703 zoom_focus = temp_focus;
1707 Editor::temporal_zoom_step (bool coarser)
1709 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1711 framecnt_t nspp = samples_per_pixel;
1719 temporal_zoom (nspp);
1723 Editor::temporal_zoom (framecnt_t fpp)
1729 framepos_t current_page = current_page_samples();
1730 framepos_t current_leftmost = leftmost_frame;
1731 framepos_t current_rightmost;
1732 framepos_t current_center;
1733 framepos_t new_page_size;
1734 framepos_t half_page_size;
1735 framepos_t leftmost_after_zoom = 0;
1737 bool in_track_canvas;
1741 if (fpp == samples_per_pixel) {
1745 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1746 // segfaults for lack of memory. If somebody decides this is not high enough I
1747 // believe it can be raisen to higher values but some limit must be in place.
1749 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1750 // all of which is used for the editor track displays. The whole day
1751 // would be 4147200000 samples, so 2592000 samples per pixel.
1753 nfpp = min (fpp, (framecnt_t) 2592000);
1754 nfpp = max ((framecnt_t) 1, nfpp);
1756 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1757 half_page_size = new_page_size / 2;
1759 switch (zoom_focus) {
1761 leftmost_after_zoom = current_leftmost;
1764 case ZoomFocusRight:
1765 current_rightmost = leftmost_frame + current_page;
1766 if (current_rightmost < new_page_size) {
1767 leftmost_after_zoom = 0;
1769 leftmost_after_zoom = current_rightmost - new_page_size;
1773 case ZoomFocusCenter:
1774 current_center = current_leftmost + (current_page/2);
1775 if (current_center < half_page_size) {
1776 leftmost_after_zoom = 0;
1778 leftmost_after_zoom = current_center - half_page_size;
1782 case ZoomFocusPlayhead:
1783 /* centre playhead */
1784 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1787 leftmost_after_zoom = 0;
1788 } else if (l > max_framepos) {
1789 leftmost_after_zoom = max_framepos - new_page_size;
1791 leftmost_after_zoom = (framepos_t) l;
1795 case ZoomFocusMouse:
1796 /* try to keep the mouse over the same point in the display */
1798 if (!mouse_frame (where, in_track_canvas)) {
1799 /* use playhead instead */
1800 where = playhead_cursor->current_frame ();
1802 if (where < half_page_size) {
1803 leftmost_after_zoom = 0;
1805 leftmost_after_zoom = where - half_page_size;
1810 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1813 leftmost_after_zoom = 0;
1814 } else if (l > max_framepos) {
1815 leftmost_after_zoom = max_framepos - new_page_size;
1817 leftmost_after_zoom = (framepos_t) l;
1824 /* try to keep the edit point in the same place */
1825 where = get_preferred_edit_position ();
1829 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1832 leftmost_after_zoom = 0;
1833 } else if (l > max_framepos) {
1834 leftmost_after_zoom = max_framepos - new_page_size;
1836 leftmost_after_zoom = (framepos_t) l;
1840 /* edit point not defined */
1847 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1849 reposition_and_zoom (leftmost_after_zoom, nfpp);
1853 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1855 /* this func helps make sure we leave a little space
1856 at each end of the editor so that the zoom doesn't fit the region
1857 precisely to the screen.
1860 GdkScreen* screen = gdk_screen_get_default ();
1861 const gint pixwidth = gdk_screen_get_width (screen);
1862 const gint mmwidth = gdk_screen_get_width_mm (screen);
1863 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1864 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1866 const framepos_t range = end - start;
1867 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1868 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1870 if (start > extra_samples) {
1871 start -= extra_samples;
1876 if (max_framepos - extra_samples > end) {
1877 end += extra_samples;
1884 Editor::temporal_zoom_region (bool both_axes)
1886 framepos_t start = max_framepos;
1888 set<TimeAxisView*> tracks;
1890 if ( !get_selection_extents(start, end) )
1893 calc_extra_zoom_edges (start, end);
1895 /* if we're zooming on both axes we need to save track heights etc.
1898 undo_visual_stack.push_back (current_visual_state (both_axes));
1900 PBD::Unwinder<bool> nsv (no_save_visual, true);
1902 temporal_zoom_by_frame (start, end);
1905 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1907 /* set visible track heights appropriately */
1909 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1910 (*t)->set_height (per_track_height);
1913 /* hide irrelevant tracks */
1915 DisplaySuspender ds;
1917 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1918 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1919 hide_track_in_display (*i);
1923 vertical_adjustment.set_value (0.0);
1926 redo_visual_stack.push_back (current_visual_state (both_axes));
1931 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1933 start = max_framepos;
1937 //ToDo: if notes are selected, set extents to that selection
1939 //ToDo: if control points are selected, set extents to that selection
1941 if ( !selection->regions.empty() ) {
1942 RegionSelection rs = get_regions_from_selection_and_entered ();
1944 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1946 if ((*i)->region()->position() < start) {
1947 start = (*i)->region()->position();
1950 if ((*i)->region()->last_frame() + 1 > end) {
1951 end = (*i)->region()->last_frame() + 1;
1955 } else if (!selection->time.empty()) {
1956 start = selection->time.start();
1957 end = selection->time.end_frame();
1959 ret = false; //no selection found
1962 if ((start == 0 && end == 0) || end < start) {
1971 Editor::temporal_zoom_selection (bool both_axes)
1973 if (!selection) return;
1975 //ToDo: if notes are selected, zoom to that
1977 //ToDo: if control points are selected, zoom to that
1979 //if region(s) are selected, zoom to that
1980 if ( !selection->regions.empty() )
1981 temporal_zoom_region (both_axes);
1983 //if a range is selected, zoom to that
1984 if (!selection->time.empty()) {
1986 framepos_t start, end;
1987 if (get_selection_extents (start, end)) {
1988 calc_extra_zoom_edges(start, end);
1989 temporal_zoom_by_frame (start, end);
1999 Editor::temporal_zoom_session ()
2001 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2004 framecnt_t start = _session->current_start_frame();
2005 framecnt_t end = _session->current_end_frame();
2007 if (_session->actively_recording () ) {
2008 framepos_t cur = playhead_cursor->current_frame ();
2010 /* recording beyond the end marker; zoom out
2011 * by 5 seconds more so that if 'follow
2012 * playhead' is active we don't immediately
2015 end = cur + _session->frame_rate() * 5;
2019 if ((start == 0 && end == 0) || end < start) {
2023 calc_extra_zoom_edges(start, end);
2025 temporal_zoom_by_frame (start, end);
2030 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2032 if (!_session) return;
2034 if ((start == 0 && end == 0) || end < start) {
2038 framepos_t range = end - start;
2040 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2042 framepos_t new_page = range;
2043 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2044 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2046 if (new_leftmost > middle) {
2050 if (new_leftmost < 0) {
2054 reposition_and_zoom (new_leftmost, new_fpp);
2058 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2064 framecnt_t range_before = frame - leftmost_frame;
2068 if (samples_per_pixel <= 1) {
2071 new_spp = samples_per_pixel + (samples_per_pixel/2);
2073 range_before += range_before/2;
2075 if (samples_per_pixel >= 1) {
2076 new_spp = samples_per_pixel - (samples_per_pixel/2);
2078 /* could bail out here since we cannot zoom any finer,
2079 but leave that to the equality test below
2081 new_spp = samples_per_pixel;
2084 range_before -= range_before/2;
2087 if (new_spp == samples_per_pixel) {
2091 /* zoom focus is automatically taken as @param frame when this
2095 framepos_t new_leftmost = frame - (framepos_t)range_before;
2097 if (new_leftmost > frame) {
2101 if (new_leftmost < 0) {
2105 reposition_and_zoom (new_leftmost, new_spp);
2110 Editor::choose_new_marker_name(string &name) {
2112 if (!UIConfiguration::instance().get_name_new_markers()) {
2113 /* don't prompt user for a new name */
2117 ArdourPrompter dialog (true);
2119 dialog.set_prompt (_("New Name:"));
2121 dialog.set_title (_("New Location Marker"));
2123 dialog.set_name ("MarkNameWindow");
2124 dialog.set_size_request (250, -1);
2125 dialog.set_position (Gtk::WIN_POS_MOUSE);
2127 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2128 dialog.set_initial_text (name);
2132 switch (dialog.run ()) {
2133 case RESPONSE_ACCEPT:
2139 dialog.get_result(name);
2146 Editor::add_location_from_selection ()
2150 if (selection->time.empty()) {
2154 if (_session == 0 || clicked_axisview == 0) {
2158 framepos_t start = selection->time[clicked_selection].start;
2159 framepos_t end = selection->time[clicked_selection].end;
2161 _session->locations()->next_available_name(rangename,"selection");
2162 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2164 begin_reversible_command (_("add marker"));
2166 XMLNode &before = _session->locations()->get_state();
2167 _session->locations()->add (location, true);
2168 XMLNode &after = _session->locations()->get_state();
2169 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2171 commit_reversible_command ();
2175 Editor::add_location_mark (framepos_t where)
2179 select_new_marker = true;
2181 _session->locations()->next_available_name(markername,"mark");
2182 if (!choose_new_marker_name(markername)) {
2185 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2186 begin_reversible_command (_("add marker"));
2188 XMLNode &before = _session->locations()->get_state();
2189 _session->locations()->add (location, true);
2190 XMLNode &after = _session->locations()->get_state();
2191 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2193 commit_reversible_command ();
2197 Editor::set_session_start_from_playhead ()
2203 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2204 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2206 XMLNode &before = loc->get_state();
2208 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2210 XMLNode &after = loc->get_state();
2212 begin_reversible_command (_("Set session start"));
2214 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2216 commit_reversible_command ();
2221 Editor::set_session_end_from_playhead ()
2227 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2228 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2230 XMLNode &before = loc->get_state();
2232 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2234 XMLNode &after = loc->get_state();
2236 begin_reversible_command (_("Set session start"));
2238 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2240 commit_reversible_command ();
2243 _session->set_end_is_free (false);
2247 Editor::add_location_from_playhead_cursor ()
2249 add_location_mark (_session->audible_frame());
2253 Editor::remove_location_at_playhead_cursor ()
2257 XMLNode &before = _session->locations()->get_state();
2258 bool removed = false;
2260 //find location(s) at this time
2261 Locations::LocationList locs;
2262 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2263 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2264 if ((*i)->is_mark()) {
2265 _session->locations()->remove (*i);
2272 begin_reversible_command (_("remove marker"));
2273 XMLNode &after = _session->locations()->get_state();
2274 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2275 commit_reversible_command ();
2280 /** Add a range marker around each selected region */
2282 Editor::add_locations_from_region ()
2284 RegionSelection rs = get_regions_from_selection_and_entered ();
2289 bool commit = false;
2291 XMLNode &before = _session->locations()->get_state();
2293 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2295 boost::shared_ptr<Region> region = (*i)->region ();
2297 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2299 _session->locations()->add (location, true);
2304 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2305 XMLNode &after = _session->locations()->get_state();
2306 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2307 commit_reversible_command ();
2311 /** Add a single range marker around all selected regions */
2313 Editor::add_location_from_region ()
2315 RegionSelection rs = get_regions_from_selection_and_entered ();
2321 XMLNode &before = _session->locations()->get_state();
2325 if (rs.size() > 1) {
2326 _session->locations()->next_available_name(markername, "regions");
2328 RegionView* rv = *(rs.begin());
2329 boost::shared_ptr<Region> region = rv->region();
2330 markername = region->name();
2333 if (!choose_new_marker_name(markername)) {
2337 // single range spanning all selected
2338 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2339 _session->locations()->add (location, true);
2341 begin_reversible_command (_("add marker"));
2342 XMLNode &after = _session->locations()->get_state();
2343 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2344 commit_reversible_command ();
2350 Editor::jump_forward_to_mark ()
2356 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2362 _session->request_locate (pos, _session->transport_rolling());
2366 Editor::jump_backward_to_mark ()
2372 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2378 _session->request_locate (pos, _session->transport_rolling());
2384 framepos_t const pos = _session->audible_frame ();
2387 _session->locations()->next_available_name (markername, "mark");
2389 if (!choose_new_marker_name (markername)) {
2393 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2397 Editor::clear_markers ()
2400 begin_reversible_command (_("clear markers"));
2402 XMLNode &before = _session->locations()->get_state();
2403 _session->locations()->clear_markers ();
2404 XMLNode &after = _session->locations()->get_state();
2405 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2407 commit_reversible_command ();
2412 Editor::clear_ranges ()
2415 begin_reversible_command (_("clear ranges"));
2417 XMLNode &before = _session->locations()->get_state();
2419 _session->locations()->clear_ranges ();
2421 XMLNode &after = _session->locations()->get_state();
2422 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2424 commit_reversible_command ();
2429 Editor::clear_locations ()
2431 begin_reversible_command (_("clear locations"));
2433 XMLNode &before = _session->locations()->get_state();
2434 _session->locations()->clear ();
2435 XMLNode &after = _session->locations()->get_state();
2436 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2438 commit_reversible_command ();
2442 Editor::unhide_markers ()
2444 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2445 Location *l = (*i).first;
2446 if (l->is_hidden() && l->is_mark()) {
2447 l->set_hidden(false, this);
2453 Editor::unhide_ranges ()
2455 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2456 Location *l = (*i).first;
2457 if (l->is_hidden() && l->is_range_marker()) {
2458 l->set_hidden(false, this);
2463 /* INSERT/REPLACE */
2466 Editor::insert_region_list_selection (float times)
2468 RouteTimeAxisView *tv = 0;
2469 boost::shared_ptr<Playlist> playlist;
2471 if (clicked_routeview != 0) {
2472 tv = clicked_routeview;
2473 } else if (!selection->tracks.empty()) {
2474 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2477 } else if (entered_track != 0) {
2478 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2485 if ((playlist = tv->playlist()) == 0) {
2489 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2494 begin_reversible_command (_("insert region"));
2495 playlist->clear_changes ();
2496 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2497 if (Config->get_edit_mode() == Ripple)
2498 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2500 _session->add_command(new StatefulDiffCommand (playlist));
2501 commit_reversible_command ();
2504 /* BUILT-IN EFFECTS */
2507 Editor::reverse_selection ()
2512 /* GAIN ENVELOPE EDITING */
2515 Editor::edit_envelope ()
2522 Editor::transition_to_rolling (bool fwd)
2528 if (_session->config.get_external_sync()) {
2529 switch (Config->get_sync_source()) {
2533 /* transport controlled by the master */
2538 if (_session->is_auditioning()) {
2539 _session->cancel_audition ();
2543 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2547 Editor::play_from_start ()
2549 _session->request_locate (_session->current_start_frame(), true);
2553 Editor::play_from_edit_point ()
2555 _session->request_locate (get_preferred_edit_position(), true);
2559 Editor::play_from_edit_point_and_return ()
2561 framepos_t start_frame;
2562 framepos_t return_frame;
2564 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2566 if (_session->transport_rolling()) {
2567 _session->request_locate (start_frame, false);
2571 /* don't reset the return frame if its already set */
2573 if ((return_frame = _session->requested_return_frame()) < 0) {
2574 return_frame = _session->audible_frame();
2577 if (start_frame >= 0) {
2578 _session->request_roll_at_and_return (start_frame, return_frame);
2583 Editor::play_selection ()
2585 framepos_t start, end;
2586 if (!get_selection_extents ( start, end))
2589 AudioRange ar (start, end, 0);
2590 list<AudioRange> lar;
2593 _session->request_play_range (&lar, true);
2597 Editor::get_preroll ()
2599 return Config->get_preroll_seconds() * _session->frame_rate();
2604 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2606 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2609 location -= get_preroll();
2611 //don't try to locate before the beginning of time
2615 //if follow_playhead is on, keep the playhead on the screen
2616 if ( _follow_playhead )
2617 if ( location < leftmost_frame )
2618 location = leftmost_frame;
2620 _session->request_locate( location );
2624 Editor::play_with_preroll ()
2627 framepos_t preroll = get_preroll();
2629 framepos_t start, end;
2630 if (!get_selection_extents ( start, end))
2633 if (start > preroll)
2634 start = start - preroll;
2636 end = end + preroll; //"post-roll"
2638 AudioRange ar (start, end, 0);
2639 list<AudioRange> lar;
2642 _session->request_play_range (&lar, true);
2647 Editor::play_location (Location& location)
2649 if (location.start() <= location.end()) {
2653 _session->request_bounded_roll (location.start(), location.end());
2657 Editor::loop_location (Location& location)
2659 if (location.start() <= location.end()) {
2665 if ((tll = transport_loop_location()) != 0) {
2666 tll->set (location.start(), location.end());
2668 // enable looping, reposition and start rolling
2669 _session->request_locate (tll->start(), true);
2670 _session->request_play_loop (true);
2675 Editor::do_layer_operation (LayerOperation op)
2677 if (selection->regions.empty ()) {
2681 bool const multiple = selection->regions.size() > 1;
2685 begin_reversible_command (_("raise regions"));
2687 begin_reversible_command (_("raise region"));
2693 begin_reversible_command (_("raise regions to top"));
2695 begin_reversible_command (_("raise region to top"));
2701 begin_reversible_command (_("lower regions"));
2703 begin_reversible_command (_("lower region"));
2709 begin_reversible_command (_("lower regions to bottom"));
2711 begin_reversible_command (_("lower region"));
2716 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2717 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2718 (*i)->clear_owned_changes ();
2721 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2722 boost::shared_ptr<Region> r = (*i)->region ();
2734 r->lower_to_bottom ();
2738 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2739 vector<Command*> cmds;
2741 _session->add_commands (cmds);
2744 commit_reversible_command ();
2748 Editor::raise_region ()
2750 do_layer_operation (Raise);
2754 Editor::raise_region_to_top ()
2756 do_layer_operation (RaiseToTop);
2760 Editor::lower_region ()
2762 do_layer_operation (Lower);
2766 Editor::lower_region_to_bottom ()
2768 do_layer_operation (LowerToBottom);
2771 /** Show the region editor for the selected regions */
2773 Editor::show_region_properties ()
2775 selection->foreach_regionview (&RegionView::show_region_editor);
2778 /** Show the midi list editor for the selected MIDI regions */
2780 Editor::show_midi_list_editor ()
2782 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2786 Editor::rename_region ()
2788 RegionSelection rs = get_regions_from_selection_and_entered ();
2794 ArdourDialog d (_("Rename Region"), true, false);
2796 Label label (_("New name:"));
2799 hbox.set_spacing (6);
2800 hbox.pack_start (label, false, false);
2801 hbox.pack_start (entry, true, true);
2803 d.get_vbox()->set_border_width (12);
2804 d.get_vbox()->pack_start (hbox, false, false);
2806 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2807 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2809 d.set_size_request (300, -1);
2811 entry.set_text (rs.front()->region()->name());
2812 entry.select_region (0, -1);
2814 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2820 int const ret = d.run();
2824 if (ret != RESPONSE_OK) {
2828 std::string str = entry.get_text();
2829 strip_whitespace_edges (str);
2831 rs.front()->region()->set_name (str);
2832 _regions->redisplay ();
2836 /** Start an audition of the first selected region */
2838 Editor::play_edit_range ()
2840 framepos_t start, end;
2842 if (get_edit_op_range (start, end)) {
2843 _session->request_bounded_roll (start, end);
2848 Editor::play_selected_region ()
2850 framepos_t start = max_framepos;
2853 RegionSelection rs = get_regions_from_selection_and_entered ();
2859 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2860 if ((*i)->region()->position() < start) {
2861 start = (*i)->region()->position();
2863 if ((*i)->region()->last_frame() + 1 > end) {
2864 end = (*i)->region()->last_frame() + 1;
2868 _session->request_bounded_roll (start, end);
2872 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2874 _session->audition_region (region);
2878 Editor::region_from_selection ()
2880 if (clicked_axisview == 0) {
2884 if (selection->time.empty()) {
2888 framepos_t start = selection->time[clicked_selection].start;
2889 framepos_t end = selection->time[clicked_selection].end;
2891 TrackViewList tracks = get_tracks_for_range_action ();
2893 framepos_t selection_cnt = end - start + 1;
2895 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2896 boost::shared_ptr<Region> current;
2897 boost::shared_ptr<Playlist> pl;
2898 framepos_t internal_start;
2901 if ((pl = (*i)->playlist()) == 0) {
2905 if ((current = pl->top_region_at (start)) == 0) {
2909 internal_start = start - current->position();
2910 RegionFactory::region_name (new_name, current->name(), true);
2914 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2915 plist.add (ARDOUR::Properties::length, selection_cnt);
2916 plist.add (ARDOUR::Properties::name, new_name);
2917 plist.add (ARDOUR::Properties::layer, 0);
2919 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2924 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2926 if (selection->time.empty() || selection->tracks.empty()) {
2930 framepos_t start, end;
2931 if (clicked_selection) {
2932 start = selection->time[clicked_selection].start;
2933 end = selection->time[clicked_selection].end;
2935 start = selection->time.start();
2936 end = selection->time.end_frame();
2939 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2940 sort_track_selection (ts);
2942 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2943 boost::shared_ptr<Region> current;
2944 boost::shared_ptr<Playlist> playlist;
2945 framepos_t internal_start;
2948 if ((playlist = (*i)->playlist()) == 0) {
2952 if ((current = playlist->top_region_at(start)) == 0) {
2956 internal_start = start - current->position();
2957 RegionFactory::region_name (new_name, current->name(), true);
2961 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2962 plist.add (ARDOUR::Properties::length, end - start + 1);
2963 plist.add (ARDOUR::Properties::name, new_name);
2965 new_regions.push_back (RegionFactory::create (current, plist));
2970 Editor::split_multichannel_region ()
2972 RegionSelection rs = get_regions_from_selection_and_entered ();
2978 vector< boost::shared_ptr<Region> > v;
2980 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2981 (*x)->region()->separate_by_channel (*_session, v);
2986 Editor::new_region_from_selection ()
2988 region_from_selection ();
2989 cancel_selection ();
2993 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2995 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2996 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2997 case Evoral::OverlapNone:
3005 * - selected tracks, or if there are none...
3006 * - tracks containing selected regions, or if there are none...
3011 Editor::get_tracks_for_range_action () const
3015 if (selection->tracks.empty()) {
3017 /* use tracks with selected regions */
3019 RegionSelection rs = selection->regions;
3021 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3022 TimeAxisView* tv = &(*i)->get_time_axis_view();
3024 if (!t.contains (tv)) {
3030 /* no regions and no tracks: use all tracks */
3036 t = selection->tracks;
3039 return t.filter_to_unique_playlists();
3043 Editor::separate_regions_between (const TimeSelection& ts)
3045 bool in_command = false;
3046 boost::shared_ptr<Playlist> playlist;
3047 RegionSelection new_selection;
3049 TrackViewList tmptracks = get_tracks_for_range_action ();
3050 sort_track_selection (tmptracks);
3052 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3054 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3060 if (!rtv->is_track()) {
3064 /* no edits to destructive tracks */
3066 if (rtv->track()->destructive()) {
3070 if ((playlist = rtv->playlist()) != 0) {
3072 playlist->clear_changes ();
3074 /* XXX need to consider musical time selections here at some point */
3076 double speed = rtv->track()->speed();
3078 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3080 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3081 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3083 latest_regionviews.clear ();
3085 playlist->partition ((framepos_t)((*t).start * speed),
3086 (framepos_t)((*t).end * speed), false);
3090 if (!latest_regionviews.empty()) {
3092 rtv->view()->foreach_regionview (sigc::bind (
3093 sigc::ptr_fun (add_if_covered),
3094 &(*t), &new_selection));
3097 begin_reversible_command (_("separate"));
3101 /* pick up changes to existing regions */
3103 vector<Command*> cmds;
3104 playlist->rdiff (cmds);
3105 _session->add_commands (cmds);
3107 /* pick up changes to the playlist itself (adds/removes)
3110 _session->add_command(new StatefulDiffCommand (playlist));
3117 // selection->set (new_selection);
3119 commit_reversible_command ();
3123 struct PlaylistState {
3124 boost::shared_ptr<Playlist> playlist;
3128 /** Take tracks from get_tracks_for_range_action and cut any regions
3129 * on those tracks so that the tracks are empty over the time
3133 Editor::separate_region_from_selection ()
3135 /* preferentially use *all* ranges in the time selection if we're in range mode
3136 to allow discontiguous operation, since get_edit_op_range() currently
3137 returns a single range.
3140 if (!selection->time.empty()) {
3142 separate_regions_between (selection->time);
3149 if (get_edit_op_range (start, end)) {
3151 AudioRange ar (start, end, 1);
3155 separate_regions_between (ts);
3161 Editor::separate_region_from_punch ()
3163 Location* loc = _session->locations()->auto_punch_location();
3165 separate_regions_using_location (*loc);
3170 Editor::separate_region_from_loop ()
3172 Location* loc = _session->locations()->auto_loop_location();
3174 separate_regions_using_location (*loc);
3179 Editor::separate_regions_using_location (Location& loc)
3181 if (loc.is_mark()) {
3185 AudioRange ar (loc.start(), loc.end(), 1);
3190 separate_regions_between (ts);
3193 /** Separate regions under the selected region */
3195 Editor::separate_under_selected_regions ()
3197 vector<PlaylistState> playlists;
3201 rs = get_regions_from_selection_and_entered();
3203 if (!_session || rs.empty()) {
3207 begin_reversible_command (_("separate region under"));
3209 list<boost::shared_ptr<Region> > regions_to_remove;
3211 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3212 // we can't just remove the region(s) in this loop because
3213 // this removes them from the RegionSelection, and they thus
3214 // disappear from underneath the iterator, and the ++i above
3215 // SEGVs in a puzzling fashion.
3217 // so, first iterate over the regions to be removed from rs and
3218 // add them to the regions_to_remove list, and then
3219 // iterate over the list to actually remove them.
3221 regions_to_remove.push_back ((*i)->region());
3224 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3226 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3229 // is this check necessary?
3233 vector<PlaylistState>::iterator i;
3235 //only take state if this is a new playlist.
3236 for (i = playlists.begin(); i != playlists.end(); ++i) {
3237 if ((*i).playlist == playlist) {
3242 if (i == playlists.end()) {
3244 PlaylistState before;
3245 before.playlist = playlist;
3246 before.before = &playlist->get_state();
3248 playlist->freeze ();
3249 playlists.push_back(before);
3252 //Partition on the region bounds
3253 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3255 //Re-add region that was just removed due to the partition operation
3256 playlist->add_region( (*rl), (*rl)->first_frame() );
3259 vector<PlaylistState>::iterator pl;
3261 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3262 (*pl).playlist->thaw ();
3263 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3266 commit_reversible_command ();
3270 Editor::crop_region_to_selection ()
3272 if (!selection->time.empty()) {
3274 crop_region_to (selection->time.start(), selection->time.end_frame());
3281 if (get_edit_op_range (start, end)) {
3282 crop_region_to (start, end);
3289 Editor::crop_region_to (framepos_t start, framepos_t end)
3291 vector<boost::shared_ptr<Playlist> > playlists;
3292 boost::shared_ptr<Playlist> playlist;
3295 if (selection->tracks.empty()) {
3296 ts = track_views.filter_to_unique_playlists();
3298 ts = selection->tracks.filter_to_unique_playlists ();
3301 sort_track_selection (ts);
3303 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3305 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3311 boost::shared_ptr<Track> t = rtv->track();
3313 if (t != 0 && ! t->destructive()) {
3315 if ((playlist = rtv->playlist()) != 0) {
3316 playlists.push_back (playlist);
3321 if (playlists.empty()) {
3326 framepos_t new_start;
3328 framecnt_t new_length;
3329 bool in_command = false;
3331 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3333 /* Only the top regions at start and end have to be cropped */
3334 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3335 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3337 vector<boost::shared_ptr<Region> > regions;
3339 if (region_at_start != 0) {
3340 regions.push_back (region_at_start);
3342 if (region_at_end != 0) {
3343 regions.push_back (region_at_end);
3346 /* now adjust lengths */
3347 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3349 pos = (*i)->position();
3350 new_start = max (start, pos);
3351 if (max_framepos - pos > (*i)->length()) {
3352 new_end = pos + (*i)->length() - 1;
3354 new_end = max_framepos;
3356 new_end = min (end, new_end);
3357 new_length = new_end - new_start + 1;
3360 begin_reversible_command (_("trim to selection"));
3363 (*i)->clear_changes ();
3364 (*i)->trim_to (new_start, new_length);
3365 _session->add_command (new StatefulDiffCommand (*i));
3370 commit_reversible_command ();
3375 Editor::region_fill_track ()
3377 boost::shared_ptr<Playlist> playlist;
3378 RegionSelection regions = get_regions_from_selection_and_entered ();
3379 RegionSelection foo;
3381 framepos_t const end = _session->current_end_frame ();
3383 if (regions.empty () || regions.end_frame () + 1 >= end) {
3387 framepos_t const start_frame = regions.start ();
3388 framepos_t const end_frame = regions.end_frame ();
3389 framecnt_t const gap = end_frame - start_frame + 1;
3391 begin_reversible_command (Operations::region_fill);
3393 selection->clear_regions ();
3395 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3397 boost::shared_ptr<Region> r ((*i)->region());
3399 TimeAxisView& tv = (*i)->get_time_axis_view();
3400 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3401 latest_regionviews.clear ();
3402 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3404 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3405 playlist = (*i)->region()->playlist();
3406 playlist->clear_changes ();
3407 playlist->duplicate_until (r, position, gap, end);
3408 _session->add_command(new StatefulDiffCommand (playlist));
3412 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3416 selection->set (foo);
3419 commit_reversible_command ();
3423 Editor::set_region_sync_position ()
3425 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3429 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3431 bool in_command = false;
3433 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3435 if (!(*r)->region()->covers (where)) {
3439 boost::shared_ptr<Region> region ((*r)->region());
3442 begin_reversible_command (_("set sync point"));
3446 region->clear_changes ();
3447 region->set_sync_position (where);
3448 _session->add_command(new StatefulDiffCommand (region));
3452 commit_reversible_command ();
3456 /** Remove the sync positions of the selection */
3458 Editor::remove_region_sync ()
3460 RegionSelection rs = get_regions_from_selection_and_entered ();
3466 begin_reversible_command (_("remove region sync"));
3468 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3470 (*i)->region()->clear_changes ();
3471 (*i)->region()->clear_sync_position ();
3472 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3475 commit_reversible_command ();
3479 Editor::naturalize_region ()
3481 RegionSelection rs = get_regions_from_selection_and_entered ();
3487 if (rs.size() > 1) {
3488 begin_reversible_command (_("move regions to original position"));
3490 begin_reversible_command (_("move region to original position"));
3493 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3494 (*i)->region()->clear_changes ();
3495 (*i)->region()->move_to_natural_position ();
3496 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3499 commit_reversible_command ();
3503 Editor::align_regions (RegionPoint what)
3505 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3511 begin_reversible_command (_("align selection"));
3513 framepos_t const position = get_preferred_edit_position ();
3515 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3516 align_region_internal ((*i)->region(), what, position);
3519 commit_reversible_command ();
3522 struct RegionSortByTime {
3523 bool operator() (const RegionView* a, const RegionView* b) {
3524 return a->region()->position() < b->region()->position();
3529 Editor::align_regions_relative (RegionPoint point)
3531 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3537 framepos_t const position = get_preferred_edit_position ();
3539 framepos_t distance = 0;
3543 list<RegionView*> sorted;
3544 rs.by_position (sorted);
3546 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3551 if (position > r->position()) {
3552 distance = position - r->position();
3554 distance = r->position() - position;
3560 if (position > r->last_frame()) {
3561 distance = position - r->last_frame();
3562 pos = r->position() + distance;
3564 distance = r->last_frame() - position;
3565 pos = r->position() - distance;
3571 pos = r->adjust_to_sync (position);
3572 if (pos > r->position()) {
3573 distance = pos - r->position();
3575 distance = r->position() - pos;
3581 if (pos == r->position()) {
3585 begin_reversible_command (_("align selection (relative)"));
3587 /* move first one specially */
3589 r->clear_changes ();
3590 r->set_position (pos);
3591 _session->add_command(new StatefulDiffCommand (r));
3593 /* move rest by the same amount */
3597 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3599 boost::shared_ptr<Region> region ((*i)->region());
3601 region->clear_changes ();
3604 region->set_position (region->position() + distance);
3606 region->set_position (region->position() - distance);
3609 _session->add_command(new StatefulDiffCommand (region));
3613 commit_reversible_command ();
3617 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3619 begin_reversible_command (_("align region"));
3620 align_region_internal (region, point, position);
3621 commit_reversible_command ();
3625 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3627 region->clear_changes ();
3631 region->set_position (region->adjust_to_sync (position));
3635 if (position > region->length()) {
3636 region->set_position (position - region->length());
3641 region->set_position (position);
3645 _session->add_command(new StatefulDiffCommand (region));
3649 Editor::trim_region_front ()
3655 Editor::trim_region_back ()
3657 trim_region (false);
3661 Editor::trim_region (bool front)
3663 framepos_t where = get_preferred_edit_position();
3664 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3670 begin_reversible_command (front ? _("trim front") : _("trim back"));
3672 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3673 if (!(*i)->region()->locked()) {
3675 (*i)->region()->clear_changes ();
3678 (*i)->region()->trim_front (where);
3679 maybe_locate_with_edit_preroll ( where );
3681 (*i)->region()->trim_end (where);
3682 maybe_locate_with_edit_preroll ( where );
3685 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3689 commit_reversible_command ();
3692 /** Trim the end of the selected regions to the position of the edit cursor */
3694 Editor::trim_region_to_loop ()
3696 Location* loc = _session->locations()->auto_loop_location();
3700 trim_region_to_location (*loc, _("trim to loop"));
3704 Editor::trim_region_to_punch ()
3706 Location* loc = _session->locations()->auto_punch_location();
3710 trim_region_to_location (*loc, _("trim to punch"));
3714 Editor::trim_region_to_location (const Location& loc, const char* str)
3716 RegionSelection rs = get_regions_from_selection_and_entered ();
3717 bool in_command = false;
3719 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3720 RegionView* rv = (*x);
3722 /* require region to span proposed trim */
3723 switch (rv->region()->coverage (loc.start(), loc.end())) {
3724 case Evoral::OverlapInternal:
3730 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3739 if (tav->track() != 0) {
3740 speed = tav->track()->speed();
3743 start = session_frame_to_track_frame (loc.start(), speed);
3744 end = session_frame_to_track_frame (loc.end(), speed);
3746 rv->region()->clear_changes ();
3747 rv->region()->trim_to (start, (end - start));
3750 begin_reversible_command (str);
3753 _session->add_command(new StatefulDiffCommand (rv->region()));
3757 commit_reversible_command ();
3762 Editor::trim_region_to_previous_region_end ()
3764 return trim_to_region(false);
3768 Editor::trim_region_to_next_region_start ()
3770 return trim_to_region(true);
3774 Editor::trim_to_region(bool forward)
3776 RegionSelection rs = get_regions_from_selection_and_entered ();
3777 bool in_command = false;
3779 boost::shared_ptr<Region> next_region;
3781 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3783 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3789 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3797 if (atav->track() != 0) {
3798 speed = atav->track()->speed();
3802 boost::shared_ptr<Region> region = arv->region();
3803 boost::shared_ptr<Playlist> playlist (region->playlist());
3805 region->clear_changes ();
3809 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3815 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3816 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3820 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3826 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3828 arv->region_changed (ARDOUR::bounds_change);
3832 begin_reversible_command (_("trim to region"));
3835 _session->add_command(new StatefulDiffCommand (region));
3839 commit_reversible_command ();
3844 Editor::unfreeze_route ()
3846 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3850 clicked_routeview->track()->unfreeze ();
3854 Editor::_freeze_thread (void* arg)
3856 return static_cast<Editor*>(arg)->freeze_thread ();
3860 Editor::freeze_thread ()
3862 /* create event pool because we may need to talk to the session */
3863 SessionEvent::create_per_thread_pool ("freeze events", 64);
3864 /* create per-thread buffers for process() tree to use */
3865 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3866 current_interthread_info->done = true;
3871 Editor::freeze_route ()
3877 /* stop transport before we start. this is important */
3879 _session->request_transport_speed (0.0);
3881 /* wait for just a little while, because the above call is asynchronous */
3883 Glib::usleep (250000);
3885 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3889 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3891 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3892 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3894 d.set_title (_("Cannot freeze"));
3899 if (clicked_routeview->track()->has_external_redirects()) {
3900 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3901 "Freezing will only process the signal as far as the first send/insert/return."),
3902 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3904 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3905 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3906 d.set_title (_("Freeze Limits"));
3908 int response = d.run ();
3911 case Gtk::RESPONSE_CANCEL:
3918 InterThreadInfo itt;
3919 current_interthread_info = &itt;
3921 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3923 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3925 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3927 while (!itt.done && !itt.cancel) {
3928 gtk_main_iteration ();
3931 pthread_join (itt.thread, 0);
3932 current_interthread_info = 0;
3936 Editor::bounce_range_selection (bool replace, bool enable_processing)
3938 if (selection->time.empty()) {
3942 TrackSelection views = selection->tracks;
3944 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3946 if (enable_processing) {
3948 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3950 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3952 _("You can't perform this operation because the processing of the signal "
3953 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3954 "You can do this without processing, which is a different operation.")
3956 d.set_title (_("Cannot bounce"));
3963 framepos_t start = selection->time[clicked_selection].start;
3964 framepos_t end = selection->time[clicked_selection].end;
3965 framepos_t cnt = end - start + 1;
3966 bool in_command = false;
3968 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3970 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3976 boost::shared_ptr<Playlist> playlist;
3978 if ((playlist = rtv->playlist()) == 0) {
3982 InterThreadInfo itt;
3984 playlist->clear_changes ();
3985 playlist->clear_owned_changes ();
3987 boost::shared_ptr<Region> r;
3989 if (enable_processing) {
3990 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3992 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4000 list<AudioRange> ranges;
4001 ranges.push_back (AudioRange (start, start+cnt, 0));
4002 playlist->cut (ranges); // discard result
4003 playlist->add_region (r, start);
4007 begin_reversible_command (_("bounce range"));
4010 vector<Command*> cmds;
4011 playlist->rdiff (cmds);
4012 _session->add_commands (cmds);
4014 _session->add_command (new StatefulDiffCommand (playlist));
4018 commit_reversible_command ();
4022 /** Delete selected regions, automation points or a time range */
4026 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4027 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4028 bool deleted = false;
4029 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4030 deleted = current_mixer_strip->delete_processors ();
4036 /** Cut selected regions, automation points or a time range */
4043 /** Copy selected regions, automation points or a time range */
4051 /** @return true if a Cut, Copy or Clear is possible */
4053 Editor::can_cut_copy () const
4055 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4062 /** Cut, copy or clear selected regions, automation points or a time range.
4063 * @param op Operation (Delete, Cut, Copy or Clear)
4066 Editor::cut_copy (CutCopyOp op)
4068 /* only cancel selection if cut/copy is successful.*/
4074 opname = _("delete");
4083 opname = _("clear");
4087 /* if we're deleting something, and the mouse is still pressed,
4088 the thing we started a drag for will be gone when we release
4089 the mouse button(s). avoid this. see part 2 at the end of
4093 if (op == Delete || op == Cut || op == Clear) {
4094 if (_drags->active ()) {
4099 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4100 cut_buffer->clear ();
4102 if (entered_marker) {
4104 /* cut/delete op while pointing at a marker */
4107 Location* loc = find_location_from_marker (entered_marker, ignored);
4109 if (_session && loc) {
4110 entered_marker = NULL;
4111 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4118 switch (mouse_mode) {
4121 begin_reversible_command (opname + ' ' + X_("MIDI"));
4123 commit_reversible_command ();
4129 bool did_edit = false;
4131 if (!selection->regions.empty() || !selection->points.empty()) {
4132 begin_reversible_command (opname + ' ' + _("objects"));
4135 if (!selection->regions.empty()) {
4136 cut_copy_regions (op, selection->regions);
4138 if (op == Cut || op == Delete) {
4139 selection->clear_regions ();
4143 if (!selection->points.empty()) {
4144 cut_copy_points (op);
4146 if (op == Cut || op == Delete) {
4147 selection->clear_points ();
4150 } else if (selection->time.empty()) {
4151 framepos_t start, end;
4152 /* no time selection, see if we can get an edit range
4155 if (get_edit_op_range (start, end)) {
4156 selection->set (start, end);
4158 } else if (!selection->time.empty()) {
4159 begin_reversible_command (opname + ' ' + _("range"));
4162 cut_copy_ranges (op);
4164 if (op == Cut || op == Delete) {
4165 selection->clear_time ();
4170 /* reset repeated paste state */
4173 commit_reversible_command ();
4176 if (op == Delete || op == Cut || op == Clear) {
4181 struct AutomationRecord {
4182 AutomationRecord () : state (0) , line(NULL) {}
4183 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4185 XMLNode* state; ///< state before any operation
4186 const AutomationLine* line; ///< line this came from
4187 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4190 /** Cut, copy or clear selected automation points.
4191 * @param op Operation (Cut, Copy or Clear)
4194 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4196 if (selection->points.empty ()) {
4200 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4201 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4203 /* Keep a record of the AutomationLists that we end up using in this operation */
4204 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4207 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4208 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4209 const AutomationLine& line = (*i)->line();
4210 const boost::shared_ptr<AutomationList> al = line.the_list();
4211 if (lists.find (al) == lists.end ()) {
4212 /* We haven't seen this list yet, so make a record for it. This includes
4213 taking a copy of its current state, in case this is needed for undo later.
4215 lists[al] = AutomationRecord (&al->get_state (), &line);
4219 if (op == Cut || op == Copy) {
4220 /* This operation will involve putting things in the cut buffer, so create an empty
4221 ControlList for each of our source lists to put the cut buffer data in.
4223 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4224 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4227 /* Add all selected points to the relevant copy ControlLists */
4228 framepos_t start = std::numeric_limits<framepos_t>::max();
4229 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4230 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4231 AutomationList::const_iterator j = (*i)->model();
4233 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4235 /* Update earliest MIDI start time in beats */
4236 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4238 /* Update earliest session start time in frames */
4239 start = std::min(start, (*i)->line().session_position(j));
4243 /* Snap start time backwards, so copy/paste is snap aligned. */
4245 if (earliest == Evoral::Beats::max()) {
4246 earliest = Evoral::Beats(); // Weird... don't offset
4248 earliest.round_down_to_beat();
4250 if (start == std::numeric_limits<double>::max()) {
4251 start = 0; // Weird... don't offset
4253 snap_to(start, RoundDownMaybe);
4256 const double line_offset = midi ? earliest.to_double() : start;
4257 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4258 /* Correct this copy list so that it is relative to the earliest
4259 start time, so relative ordering between points is preserved
4260 when copying from several lists and the paste starts at the
4261 earliest copied piece of data. */
4262 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4263 (*j)->when -= line_offset;
4266 /* And add it to the cut buffer */
4267 cut_buffer->add (i->second.copy);
4271 if (op == Delete || op == Cut) {
4272 /* This operation needs to remove things from the main AutomationList, so do that now */
4274 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4275 i->first->freeze ();
4278 /* Remove each selected point from its AutomationList */
4279 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4280 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4281 al->erase ((*i)->model ());
4284 /* Thaw the lists and add undo records for them */
4285 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4286 boost::shared_ptr<AutomationList> al = i->first;
4288 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4293 /** Cut, copy or clear selected automation points.
4294 * @param op Operation (Cut, Copy or Clear)
4297 Editor::cut_copy_midi (CutCopyOp op)
4299 Evoral::Beats earliest = Evoral::Beats::max();
4300 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4301 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4303 if (!mrv->selection().empty()) {
4304 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4306 mrv->cut_copy_clear (op);
4308 /* XXX: not ideal, as there may be more than one track involved in the selection */
4309 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4313 if (!selection->points.empty()) {
4314 cut_copy_points (op, earliest, true);
4315 if (op == Cut || op == Delete) {
4316 selection->clear_points ();
4321 struct lt_playlist {
4322 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4323 return a.playlist < b.playlist;
4327 struct PlaylistMapping {
4329 boost::shared_ptr<Playlist> pl;
4331 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4334 /** Remove `clicked_regionview' */
4336 Editor::remove_clicked_region ()
4338 if (clicked_routeview == 0 || clicked_regionview == 0) {
4342 begin_reversible_command (_("remove region"));
4344 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4346 playlist->clear_changes ();
4347 playlist->clear_owned_changes ();
4348 playlist->remove_region (clicked_regionview->region());
4349 if (Config->get_edit_mode() == Ripple)
4350 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4352 /* We might have removed regions, which alters other regions' layering_index,
4353 so we need to do a recursive diff here.
4355 vector<Command*> cmds;
4356 playlist->rdiff (cmds);
4357 _session->add_commands (cmds);
4359 _session->add_command(new StatefulDiffCommand (playlist));
4360 commit_reversible_command ();
4364 /** Remove the selected regions */
4366 Editor::remove_selected_regions ()
4368 RegionSelection rs = get_regions_from_selection_and_entered ();
4370 if (!_session || rs.empty()) {
4374 list<boost::shared_ptr<Region> > regions_to_remove;
4376 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4377 // we can't just remove the region(s) in this loop because
4378 // this removes them from the RegionSelection, and they thus
4379 // disappear from underneath the iterator, and the ++i above
4380 // SEGVs in a puzzling fashion.
4382 // so, first iterate over the regions to be removed from rs and
4383 // add them to the regions_to_remove list, and then
4384 // iterate over the list to actually remove them.
4386 regions_to_remove.push_back ((*i)->region());
4389 vector<boost::shared_ptr<Playlist> > playlists;
4391 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4393 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4396 // is this check necessary?
4400 /* get_regions_from_selection_and_entered() guarantees that
4401 the playlists involved are unique, so there is no need
4405 playlists.push_back (playlist);
4407 playlist->clear_changes ();
4408 playlist->clear_owned_changes ();
4409 playlist->freeze ();
4410 playlist->remove_region (*rl);
4411 if (Config->get_edit_mode() == Ripple)
4412 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4416 vector<boost::shared_ptr<Playlist> >::iterator pl;
4417 bool in_command = false;
4419 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4422 /* We might have removed regions, which alters other regions' layering_index,
4423 so we need to do a recursive diff here.
4427 begin_reversible_command (_("remove region"));
4430 vector<Command*> cmds;
4431 (*pl)->rdiff (cmds);
4432 _session->add_commands (cmds);
4434 _session->add_command(new StatefulDiffCommand (*pl));
4438 commit_reversible_command ();
4442 /** Cut, copy or clear selected regions.
4443 * @param op Operation (Cut, Copy or Clear)
4446 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4448 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4449 a map when we want ordered access to both elements. i think.
4452 vector<PlaylistMapping> pmap;
4454 framepos_t first_position = max_framepos;
4456 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4457 FreezeList freezelist;
4459 /* get ordering correct before we cut/copy */
4461 rs.sort_by_position_and_track ();
4463 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4465 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4467 if (op == Cut || op == Clear || op == Delete) {
4468 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4471 FreezeList::iterator fl;
4473 // only take state if this is a new playlist.
4474 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4480 if (fl == freezelist.end()) {
4481 pl->clear_changes();
4482 pl->clear_owned_changes ();
4484 freezelist.insert (pl);
4489 TimeAxisView* tv = &(*x)->get_time_axis_view();
4490 vector<PlaylistMapping>::iterator z;
4492 for (z = pmap.begin(); z != pmap.end(); ++z) {
4493 if ((*z).tv == tv) {
4498 if (z == pmap.end()) {
4499 pmap.push_back (PlaylistMapping (tv));
4503 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4505 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4508 /* region not yet associated with a playlist (e.g. unfinished
4515 TimeAxisView& tv = (*x)->get_time_axis_view();
4516 boost::shared_ptr<Playlist> npl;
4517 RegionSelection::iterator tmp;
4524 vector<PlaylistMapping>::iterator z;
4526 for (z = pmap.begin(); z != pmap.end(); ++z) {
4527 if ((*z).tv == &tv) {
4532 assert (z != pmap.end());
4535 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4543 boost::shared_ptr<Region> r = (*x)->region();
4544 boost::shared_ptr<Region> _xx;
4550 pl->remove_region (r);
4551 if (Config->get_edit_mode() == Ripple)
4552 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4556 _xx = RegionFactory::create (r);
4557 npl->add_region (_xx, r->position() - first_position);
4558 pl->remove_region (r);
4559 if (Config->get_edit_mode() == Ripple)
4560 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4564 /* copy region before adding, so we're not putting same object into two different playlists */
4565 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4569 pl->remove_region (r);
4570 if (Config->get_edit_mode() == Ripple)
4571 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4580 list<boost::shared_ptr<Playlist> > foo;
4582 /* the pmap is in the same order as the tracks in which selected regions occurred */
4584 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4587 foo.push_back ((*i).pl);
4592 cut_buffer->set (foo);
4596 _last_cut_copy_source_track = 0;
4598 _last_cut_copy_source_track = pmap.front().tv;
4602 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4605 /* We might have removed regions, which alters other regions' layering_index,
4606 so we need to do a recursive diff here.
4608 vector<Command*> cmds;
4609 (*pl)->rdiff (cmds);
4610 _session->add_commands (cmds);
4612 _session->add_command (new StatefulDiffCommand (*pl));
4617 Editor::cut_copy_ranges (CutCopyOp op)
4619 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4621 /* Sort the track selection now, so that it if is used, the playlists
4622 selected by the calls below to cut_copy_clear are in the order that
4623 their tracks appear in the editor. This makes things like paste
4624 of ranges work properly.
4627 sort_track_selection (ts);
4630 if (!entered_track) {
4633 ts.push_back (entered_track);
4636 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4637 (*i)->cut_copy_clear (*selection, op);
4642 Editor::paste (float times, bool from_context)
4644 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4646 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0));
4650 Editor::mouse_paste ()
4655 if (!mouse_frame (where, ignored)) {
4660 paste_internal (where, 1, get_grid_music_divisions (0));
4664 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4666 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4668 if (cut_buffer->empty(internal_editing())) {
4672 if (position == max_framepos) {
4673 position = get_preferred_edit_position();
4674 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4677 if (position == last_paste_pos) {
4678 /* repeated paste in the same position */
4681 /* paste in new location, reset repeated paste state */
4683 last_paste_pos = position;
4686 /* get everything in the correct order */
4689 if (!selection->tracks.empty()) {
4690 /* If there is a track selection, paste into exactly those tracks and
4691 only those tracks. This allows the user to be explicit and override
4692 the below "do the reasonable thing" logic. */
4693 ts = selection->tracks.filter_to_unique_playlists ();
4694 sort_track_selection (ts);
4696 /* Figure out which track to base the paste at. */
4697 TimeAxisView* base_track = NULL;
4698 if (_edit_point == Editing::EditAtMouse && entered_track) {
4699 /* With the mouse edit point, paste onto the track under the mouse. */
4700 base_track = entered_track;
4701 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4702 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4703 base_track = &entered_regionview->get_time_axis_view();
4704 } else if (_last_cut_copy_source_track) {
4705 /* Paste to the track that the cut/copy came from (see mantis #333). */
4706 base_track = _last_cut_copy_source_track;
4708 /* This is "impossible" since we've copied... well, do nothing. */
4712 /* Walk up to parent if necessary, so base track is a route. */
4713 while (base_track->get_parent()) {
4714 base_track = base_track->get_parent();
4717 /* Add base track and all tracks below it. The paste logic will select
4718 the appropriate object types from the cut buffer in relative order. */
4719 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4720 if ((*i)->order() >= base_track->order()) {
4725 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4726 sort_track_selection (ts);
4728 /* Add automation children of each track in order, for pasting several lines. */
4729 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4730 /* Add any automation children for pasting several lines */
4731 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4736 typedef RouteTimeAxisView::AutomationTracks ATracks;
4737 const ATracks& atracks = rtv->automation_tracks();
4738 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4739 i = ts.insert(i, a->second.get());
4744 /* We now have a list of trackviews starting at base_track, including
4745 automation children, in the order shown in the editor, e.g. R1,
4746 R1.A1, R1.A2, R2, R2.A1, ... */
4749 begin_reversible_command (Operations::paste);
4751 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4752 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4753 /* Only one line copied, and one automation track selected. Do a
4754 "greedy" paste from one automation type to another. */
4756 PasteContext ctx(paste_count, times, ItemCounts(), true);
4757 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4761 /* Paste into tracks */
4763 PasteContext ctx(paste_count, times, ItemCounts(), false);
4764 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4765 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4769 commit_reversible_command ();
4773 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4775 if (regions.empty ()) {
4779 boost::shared_ptr<Playlist> playlist;
4780 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4781 RegionSelection foo;
4783 framepos_t const start_frame = regions.start ();
4784 framepos_t const end_frame = regions.end_frame ();
4785 framecnt_t const gap = end_frame - start_frame + 1;
4787 begin_reversible_command (Operations::duplicate_region);
4789 selection->clear_regions ();
4791 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4793 boost::shared_ptr<Region> r ((*i)->region());
4795 TimeAxisView& tv = (*i)->get_time_axis_view();
4796 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4797 latest_regionviews.clear ();
4798 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4800 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4801 playlist = (*i)->region()->playlist();
4802 playlist->clear_changes ();
4803 playlist->duplicate (r, position, gap, times);
4804 _session->add_command(new StatefulDiffCommand (playlist));
4808 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4812 selection->set (foo);
4815 commit_reversible_command ();
4819 Editor::duplicate_selection (float times)
4821 if (selection->time.empty() || selection->tracks.empty()) {
4825 boost::shared_ptr<Playlist> playlist;
4827 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4829 bool in_command = false;
4831 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4832 if ((playlist = (*i)->playlist()) == 0) {
4835 playlist->clear_changes ();
4837 if (clicked_selection) {
4838 playlist->duplicate_range (selection->time[clicked_selection], times);
4840 playlist->duplicate_ranges (selection->time, times);
4844 begin_reversible_command (_("duplicate range selection"));
4847 _session->add_command (new StatefulDiffCommand (playlist));
4852 // now "move" range selection to after the current range selection
4853 framecnt_t distance = 0;
4855 if (clicked_selection) {
4856 distance = selection->time[clicked_selection].end -
4857 selection->time[clicked_selection].start;
4859 distance = selection->time.end_frame() - selection->time.start();
4862 selection->move_time (distance);
4864 commit_reversible_command ();
4868 /** Reset all selected points to the relevant default value */
4870 Editor::reset_point_selection ()
4872 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4873 ARDOUR::AutomationList::iterator j = (*i)->model ();
4874 (*j)->value = (*i)->line().the_list()->default_value ();
4879 Editor::center_playhead ()
4881 float const page = _visible_canvas_width * samples_per_pixel;
4882 center_screen_internal (playhead_cursor->current_frame (), page);
4886 Editor::center_edit_point ()
4888 float const page = _visible_canvas_width * samples_per_pixel;
4889 center_screen_internal (get_preferred_edit_position(), page);
4892 /** Caller must begin and commit a reversible command */
4894 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4896 playlist->clear_changes ();
4898 _session->add_command (new StatefulDiffCommand (playlist));
4902 Editor::nudge_track (bool use_edit, bool forwards)
4904 boost::shared_ptr<Playlist> playlist;
4905 framepos_t distance;
4906 framepos_t next_distance;
4910 start = get_preferred_edit_position();
4915 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4919 if (selection->tracks.empty()) {
4923 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4924 bool in_command = false;
4926 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4928 if ((playlist = (*i)->playlist()) == 0) {
4932 playlist->clear_changes ();
4933 playlist->clear_owned_changes ();
4935 playlist->nudge_after (start, distance, forwards);
4938 begin_reversible_command (_("nudge track"));
4941 vector<Command*> cmds;
4943 playlist->rdiff (cmds);
4944 _session->add_commands (cmds);
4946 _session->add_command (new StatefulDiffCommand (playlist));
4950 commit_reversible_command ();
4955 Editor::remove_last_capture ()
4957 vector<string> choices;
4964 if (Config->get_verify_remove_last_capture()) {
4965 prompt = _("Do you really want to destroy the last capture?"
4966 "\n(This is destructive and cannot be undone)");
4968 choices.push_back (_("No, do nothing."));
4969 choices.push_back (_("Yes, destroy it."));
4971 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4973 if (prompter.run () == 1) {
4974 _session->remove_last_capture ();
4975 _regions->redisplay ();
4979 _session->remove_last_capture();
4980 _regions->redisplay ();
4985 Editor::normalize_region ()
4991 RegionSelection rs = get_regions_from_selection_and_entered ();
4997 NormalizeDialog dialog (rs.size() > 1);
4999 if (dialog.run () == RESPONSE_CANCEL) {
5003 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5006 /* XXX: should really only count audio regions here */
5007 int const regions = rs.size ();
5009 /* Make a list of the selected audio regions' maximum amplitudes, and also
5010 obtain the maximum amplitude of them all.
5012 list<double> max_amps;
5014 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5015 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5017 dialog.descend (1.0 / regions);
5018 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5021 /* the user cancelled the operation */
5025 max_amps.push_back (a);
5026 max_amp = max (max_amp, a);
5031 list<double>::const_iterator a = max_amps.begin ();
5032 bool in_command = false;
5034 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5035 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5040 arv->region()->clear_changes ();
5042 double const amp = dialog.normalize_individually() ? *a : max_amp;
5044 arv->audio_region()->normalize (amp, dialog.target ());
5047 begin_reversible_command (_("normalize"));
5050 _session->add_command (new StatefulDiffCommand (arv->region()));
5056 commit_reversible_command ();
5062 Editor::reset_region_scale_amplitude ()
5068 RegionSelection rs = get_regions_from_selection_and_entered ();
5074 bool in_command = false;
5076 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5077 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5080 arv->region()->clear_changes ();
5081 arv->audio_region()->set_scale_amplitude (1.0f);
5084 begin_reversible_command ("reset gain");
5087 _session->add_command (new StatefulDiffCommand (arv->region()));
5091 commit_reversible_command ();
5096 Editor::adjust_region_gain (bool up)
5098 RegionSelection rs = get_regions_from_selection_and_entered ();
5100 if (!_session || rs.empty()) {
5104 bool in_command = false;
5106 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5107 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5112 arv->region()->clear_changes ();
5114 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5122 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5125 begin_reversible_command ("adjust region gain");
5128 _session->add_command (new StatefulDiffCommand (arv->region()));
5132 commit_reversible_command ();
5138 Editor::reverse_region ()
5144 Reverse rev (*_session);
5145 apply_filter (rev, _("reverse regions"));
5149 Editor::strip_region_silence ()
5155 RegionSelection rs = get_regions_from_selection_and_entered ();
5161 std::list<RegionView*> audio_only;
5163 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5164 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5166 audio_only.push_back (arv);
5170 assert (!audio_only.empty());
5172 StripSilenceDialog d (_session, audio_only);
5173 int const r = d.run ();
5177 if (r == Gtk::RESPONSE_OK) {
5178 ARDOUR::AudioIntervalMap silences;
5179 d.silences (silences);
5180 StripSilence s (*_session, silences, d.fade_length());
5182 apply_filter (s, _("strip silence"), &d);
5187 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5189 Evoral::Sequence<Evoral::Beats>::Notes selected;
5190 mrv.selection_as_notelist (selected, true);
5192 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5193 v.push_back (selected);
5195 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5196 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5198 return op (mrv.midi_region()->model(), pos_beats, v);
5202 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5208 bool in_command = false;
5210 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5211 RegionSelection::const_iterator tmp = r;
5214 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5217 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5220 begin_reversible_command (op.name ());
5224 _session->add_command (cmd);
5232 commit_reversible_command ();
5237 Editor::fork_region ()
5239 RegionSelection rs = get_regions_from_selection_and_entered ();
5245 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5246 bool in_command = false;
5250 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5251 RegionSelection::iterator tmp = r;
5254 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5258 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5259 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5260 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5263 begin_reversible_command (_("Fork Region(s)"));
5266 playlist->clear_changes ();
5267 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5268 _session->add_command(new StatefulDiffCommand (playlist));
5270 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5278 commit_reversible_command ();
5283 Editor::quantize_region ()
5286 quantize_regions(get_regions_from_selection_and_entered ());
5291 Editor::quantize_regions (const RegionSelection& rs)
5293 if (rs.n_midi_regions() == 0) {
5297 if (!quantize_dialog) {
5298 quantize_dialog = new QuantizeDialog (*this);
5301 quantize_dialog->present ();
5302 const int r = quantize_dialog->run ();
5303 quantize_dialog->hide ();
5305 if (r == Gtk::RESPONSE_OK) {
5306 Quantize quant (quantize_dialog->snap_start(),
5307 quantize_dialog->snap_end(),
5308 quantize_dialog->start_grid_size(),
5309 quantize_dialog->end_grid_size(),
5310 quantize_dialog->strength(),
5311 quantize_dialog->swing(),
5312 quantize_dialog->threshold());
5314 apply_midi_note_edit_op (quant, rs);
5319 Editor::legatize_region (bool shrink_only)
5322 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5327 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5329 if (rs.n_midi_regions() == 0) {
5333 Legatize legatize(shrink_only);
5334 apply_midi_note_edit_op (legatize, rs);
5338 Editor::transform_region ()
5341 transform_regions(get_regions_from_selection_and_entered ());
5346 Editor::transform_regions (const RegionSelection& rs)
5348 if (rs.n_midi_regions() == 0) {
5355 const int r = td.run();
5358 if (r == Gtk::RESPONSE_OK) {
5359 Transform transform(td.get());
5360 apply_midi_note_edit_op(transform, rs);
5365 Editor::transpose_region ()
5368 transpose_regions(get_regions_from_selection_and_entered ());
5373 Editor::transpose_regions (const RegionSelection& rs)
5375 if (rs.n_midi_regions() == 0) {
5380 int const r = d.run ();
5382 if (r == RESPONSE_ACCEPT) {
5383 Transpose transpose(d.semitones ());
5384 apply_midi_note_edit_op (transpose, rs);
5389 Editor::insert_patch_change (bool from_context)
5391 RegionSelection rs = get_regions_from_selection_and_entered ();
5397 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5399 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5400 there may be more than one, but the PatchChangeDialog can only offer
5401 one set of patch menus.
5403 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5405 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5406 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5408 if (d.run() == RESPONSE_CANCEL) {
5412 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5413 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5415 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5416 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5423 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5425 RegionSelection rs = get_regions_from_selection_and_entered ();
5431 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5432 bool in_command = false;
5437 int const N = rs.size ();
5439 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5440 RegionSelection::iterator tmp = r;
5443 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5445 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5448 progress->descend (1.0 / N);
5451 if (arv->audio_region()->apply (filter, progress) == 0) {
5453 playlist->clear_changes ();
5454 playlist->clear_owned_changes ();
5457 begin_reversible_command (command);
5461 if (filter.results.empty ()) {
5463 /* no regions returned; remove the old one */
5464 playlist->remove_region (arv->region ());
5468 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5470 /* first region replaces the old one */
5471 playlist->replace_region (arv->region(), *res, (*res)->position());
5475 while (res != filter.results.end()) {
5476 playlist->add_region (*res, (*res)->position());
5482 /* We might have removed regions, which alters other regions' layering_index,
5483 so we need to do a recursive diff here.
5485 vector<Command*> cmds;
5486 playlist->rdiff (cmds);
5487 _session->add_commands (cmds);
5489 _session->add_command(new StatefulDiffCommand (playlist));
5493 progress->ascend ();
5502 commit_reversible_command ();
5507 Editor::external_edit_region ()
5513 Editor::reset_region_gain_envelopes ()
5515 RegionSelection rs = get_regions_from_selection_and_entered ();
5517 if (!_session || rs.empty()) {
5521 bool in_command = false;
5523 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5524 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5526 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5527 XMLNode& before (alist->get_state());
5529 arv->audio_region()->set_default_envelope ();
5532 begin_reversible_command (_("reset region gain"));
5535 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5540 commit_reversible_command ();
5545 Editor::set_region_gain_visibility (RegionView* rv)
5547 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5549 arv->update_envelope_visibility();
5554 Editor::set_gain_envelope_visibility ()
5560 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5561 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5563 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5569 Editor::toggle_gain_envelope_active ()
5571 if (_ignore_region_action) {
5575 RegionSelection rs = get_regions_from_selection_and_entered ();
5577 if (!_session || rs.empty()) {
5581 bool in_command = false;
5583 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5584 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5586 arv->region()->clear_changes ();
5587 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5590 begin_reversible_command (_("region gain envelope active"));
5593 _session->add_command (new StatefulDiffCommand (arv->region()));
5598 commit_reversible_command ();
5603 Editor::toggle_region_lock ()
5605 if (_ignore_region_action) {
5609 RegionSelection rs = get_regions_from_selection_and_entered ();
5611 if (!_session || rs.empty()) {
5615 begin_reversible_command (_("toggle region lock"));
5617 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5618 (*i)->region()->clear_changes ();
5619 (*i)->region()->set_locked (!(*i)->region()->locked());
5620 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5623 commit_reversible_command ();
5627 Editor::toggle_region_video_lock ()
5629 if (_ignore_region_action) {
5633 RegionSelection rs = get_regions_from_selection_and_entered ();
5635 if (!_session || rs.empty()) {
5639 begin_reversible_command (_("Toggle Video Lock"));
5641 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5642 (*i)->region()->clear_changes ();
5643 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5644 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5647 commit_reversible_command ();
5651 Editor::toggle_region_lock_style ()
5653 if (_ignore_region_action) {
5657 RegionSelection rs = get_regions_from_selection_and_entered ();
5659 if (!_session || rs.empty()) {
5663 begin_reversible_command (_("region lock style"));
5665 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5666 (*i)->region()->clear_changes ();
5667 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5668 (*i)->region()->set_position_lock_style (ns);
5669 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5672 commit_reversible_command ();
5676 Editor::toggle_opaque_region ()
5678 if (_ignore_region_action) {
5682 RegionSelection rs = get_regions_from_selection_and_entered ();
5684 if (!_session || rs.empty()) {
5688 begin_reversible_command (_("change region opacity"));
5690 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5691 (*i)->region()->clear_changes ();
5692 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5693 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5696 commit_reversible_command ();
5700 Editor::toggle_record_enable ()
5702 bool new_state = false;
5704 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5705 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5708 if (!rtav->is_track())
5712 new_state = !rtav->track()->rec_enable_control()->get_value();
5716 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5721 Editor::toggle_solo ()
5723 bool new_state = false;
5725 boost::shared_ptr<ControlList> cl (new ControlList);
5727 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5728 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5735 new_state = !rtav->route()->soloed ();
5739 cl->push_back (rtav->route()->solo_control());
5742 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5746 Editor::toggle_mute ()
5748 bool new_state = false;
5750 boost::shared_ptr<RouteList> rl (new RouteList);
5752 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5753 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5760 new_state = !rtav->route()->muted();
5764 rl->push_back (rtav->route());
5767 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5771 Editor::toggle_solo_isolate ()
5777 Editor::fade_range ()
5779 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5781 begin_reversible_command (_("fade range"));
5783 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5784 (*i)->fade_range (selection->time);
5787 commit_reversible_command ();
5792 Editor::set_fade_length (bool in)
5794 RegionSelection rs = get_regions_from_selection_and_entered ();
5800 /* we need a region to measure the offset from the start */
5802 RegionView* rv = rs.front ();
5804 framepos_t pos = get_preferred_edit_position();
5808 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5809 /* edit point is outside the relevant region */
5814 if (pos <= rv->region()->position()) {
5818 len = pos - rv->region()->position();
5819 cmd = _("set fade in length");
5821 if (pos >= rv->region()->last_frame()) {
5825 len = rv->region()->last_frame() - pos;
5826 cmd = _("set fade out length");
5829 bool in_command = false;
5831 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5832 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5838 boost::shared_ptr<AutomationList> alist;
5840 alist = tmp->audio_region()->fade_in();
5842 alist = tmp->audio_region()->fade_out();
5845 XMLNode &before = alist->get_state();
5848 tmp->audio_region()->set_fade_in_length (len);
5849 tmp->audio_region()->set_fade_in_active (true);
5851 tmp->audio_region()->set_fade_out_length (len);
5852 tmp->audio_region()->set_fade_out_active (true);
5856 begin_reversible_command (cmd);
5859 XMLNode &after = alist->get_state();
5860 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5864 commit_reversible_command ();
5869 Editor::set_fade_in_shape (FadeShape shape)
5871 RegionSelection rs = get_regions_from_selection_and_entered ();
5876 bool in_command = false;
5878 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5879 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5885 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5886 XMLNode &before = alist->get_state();
5888 tmp->audio_region()->set_fade_in_shape (shape);
5891 begin_reversible_command (_("set fade in shape"));
5894 XMLNode &after = alist->get_state();
5895 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5899 commit_reversible_command ();
5904 Editor::set_fade_out_shape (FadeShape shape)
5906 RegionSelection rs = get_regions_from_selection_and_entered ();
5911 bool in_command = false;
5913 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5914 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5920 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5921 XMLNode &before = alist->get_state();
5923 tmp->audio_region()->set_fade_out_shape (shape);
5926 begin_reversible_command (_("set fade out shape"));
5929 XMLNode &after = alist->get_state();
5930 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5934 commit_reversible_command ();
5939 Editor::set_fade_in_active (bool yn)
5941 RegionSelection rs = get_regions_from_selection_and_entered ();
5946 bool in_command = false;
5948 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5949 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5956 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5958 ar->clear_changes ();
5959 ar->set_fade_in_active (yn);
5962 begin_reversible_command (_("set fade in active"));
5965 _session->add_command (new StatefulDiffCommand (ar));
5969 commit_reversible_command ();
5974 Editor::set_fade_out_active (bool yn)
5976 RegionSelection rs = get_regions_from_selection_and_entered ();
5981 bool in_command = false;
5983 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5984 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5990 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5992 ar->clear_changes ();
5993 ar->set_fade_out_active (yn);
5996 begin_reversible_command (_("set fade out active"));
5999 _session->add_command(new StatefulDiffCommand (ar));
6003 commit_reversible_command ();
6008 Editor::toggle_region_fades (int dir)
6010 if (_ignore_region_action) {
6014 boost::shared_ptr<AudioRegion> ar;
6017 RegionSelection rs = get_regions_from_selection_and_entered ();
6023 RegionSelection::iterator i;
6024 for (i = rs.begin(); i != rs.end(); ++i) {
6025 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6027 yn = ar->fade_out_active ();
6029 yn = ar->fade_in_active ();
6035 if (i == rs.end()) {
6039 /* XXX should this undo-able? */
6040 bool in_command = false;
6042 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6043 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6046 ar->clear_changes ();
6048 if (dir == 1 || dir == 0) {
6049 ar->set_fade_in_active (!yn);
6052 if (dir == -1 || dir == 0) {
6053 ar->set_fade_out_active (!yn);
6056 begin_reversible_command (_("toggle fade active"));
6059 _session->add_command(new StatefulDiffCommand (ar));
6063 commit_reversible_command ();
6068 /** Update region fade visibility after its configuration has been changed */
6070 Editor::update_region_fade_visibility ()
6072 bool _fade_visibility = _session->config.get_show_region_fades ();
6074 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6075 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6077 if (_fade_visibility) {
6078 v->audio_view()->show_all_fades ();
6080 v->audio_view()->hide_all_fades ();
6087 Editor::set_edit_point ()
6092 if (!mouse_frame (where, ignored)) {
6098 if (selection->markers.empty()) {
6100 mouse_add_new_marker (where);
6105 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6108 loc->move_to (where);
6114 Editor::set_playhead_cursor ()
6116 if (entered_marker) {
6117 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6122 if (!mouse_frame (where, ignored)) {
6129 _session->request_locate (where, _session->transport_rolling());
6133 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6134 cancel_time_selection();
6139 Editor::split_region ()
6141 if (_drags->active ()) {
6145 //if a range is selected, separate it
6146 if ( !selection->time.empty()) {
6147 separate_regions_between (selection->time);
6151 //if no range was selected, try to find some regions to split
6152 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6154 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6156 framepos_t where = get_preferred_edit_position ();
6162 if (snap_musical()) {
6163 split_regions_at (where, rs, get_grid_music_divisions (0));
6165 split_regions_at (where, rs, 0);
6171 Editor::select_next_route()
6173 if (selection->tracks.empty()) {
6174 selection->set (track_views.front());
6178 TimeAxisView* current = selection->tracks.front();
6182 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6184 if (*i == current) {
6186 if (i != track_views.end()) {
6189 current = (*(track_views.begin()));
6190 //selection->set (*(track_views.begin()));
6196 rui = dynamic_cast<RouteUI *>(current);
6198 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6200 selection->set (current);
6202 ensure_time_axis_view_is_visible (*current, false);
6206 Editor::select_prev_route()
6208 if (selection->tracks.empty()) {
6209 selection->set (track_views.front());
6213 TimeAxisView* current = selection->tracks.front();
6217 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6219 if (*i == current) {
6221 if (i != track_views.rend()) {
6224 current = *(track_views.rbegin());
6229 rui = dynamic_cast<RouteUI *>(current);
6231 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6233 selection->set (current);
6235 ensure_time_axis_view_is_visible (*current, false);
6239 Editor::set_loop_from_selection (bool play)
6241 if (_session == 0) {
6245 framepos_t start, end;
6246 if (!get_selection_extents ( start, end))
6249 set_loop_range (start, end, _("set loop range from selection"));
6252 _session->request_play_loop (true, true);
6257 Editor::set_loop_from_region (bool play)
6259 framepos_t start, end;
6260 if (!get_selection_extents ( start, end))
6263 set_loop_range (start, end, _("set loop range from region"));
6266 _session->request_locate (start, true);
6267 _session->request_play_loop (true);
6272 Editor::set_punch_from_selection ()
6274 if (_session == 0) {
6278 framepos_t start, end;
6279 if (!get_selection_extents ( start, end))
6282 set_punch_range (start, end, _("set punch range from selection"));
6286 Editor::set_session_extents_from_selection ()
6288 if (_session == 0) {
6292 framepos_t start, end;
6293 if (!get_selection_extents ( start, end))
6297 if ((loc = _session->locations()->session_range_location()) == 0) {
6298 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6300 XMLNode &before = loc->get_state();
6302 _session->set_session_extents (start, end);
6304 XMLNode &after = loc->get_state();
6306 begin_reversible_command (_("set session start/end from selection"));
6308 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6310 commit_reversible_command ();
6313 _session->set_end_is_free (false);
6317 Editor::set_punch_start_from_edit_point ()
6321 framepos_t start = 0;
6322 framepos_t end = max_framepos;
6324 //use the existing punch end, if any
6325 Location* tpl = transport_punch_location();
6330 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6331 start = _session->audible_frame();
6333 start = get_preferred_edit_position();
6336 //snap the selection start/end
6339 //if there's not already a sensible selection endpoint, go "forever"
6340 if ( start > end ) {
6344 set_punch_range (start, end, _("set punch start from EP"));
6350 Editor::set_punch_end_from_edit_point ()
6354 framepos_t start = 0;
6355 framepos_t end = max_framepos;
6357 //use the existing punch start, if any
6358 Location* tpl = transport_punch_location();
6360 start = tpl->start();
6363 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6364 end = _session->audible_frame();
6366 end = get_preferred_edit_position();
6369 //snap the selection start/end
6372 set_punch_range (start, end, _("set punch end from EP"));
6378 Editor::set_loop_start_from_edit_point ()
6382 framepos_t start = 0;
6383 framepos_t end = max_framepos;
6385 //use the existing loop end, if any
6386 Location* tpl = transport_loop_location();
6391 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6392 start = _session->audible_frame();
6394 start = get_preferred_edit_position();
6397 //snap the selection start/end
6400 //if there's not already a sensible selection endpoint, go "forever"
6401 if ( start > end ) {
6405 set_loop_range (start, end, _("set loop start from EP"));
6411 Editor::set_loop_end_from_edit_point ()
6415 framepos_t start = 0;
6416 framepos_t end = max_framepos;
6418 //use the existing loop start, if any
6419 Location* tpl = transport_loop_location();
6421 start = tpl->start();
6424 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6425 end = _session->audible_frame();
6427 end = get_preferred_edit_position();
6430 //snap the selection start/end
6433 set_loop_range (start, end, _("set loop end from EP"));
6438 Editor::set_punch_from_region ()
6440 framepos_t start, end;
6441 if (!get_selection_extents ( start, end))
6444 set_punch_range (start, end, _("set punch range from region"));
6448 Editor::pitch_shift_region ()
6450 RegionSelection rs = get_regions_from_selection_and_entered ();
6452 RegionSelection audio_rs;
6453 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6454 if (dynamic_cast<AudioRegionView*> (*i)) {
6455 audio_rs.push_back (*i);
6459 if (audio_rs.empty()) {
6463 pitch_shift (audio_rs, 1.2);
6467 Editor::set_tempo_from_region ()
6469 RegionSelection rs = get_regions_from_selection_and_entered ();
6471 if (!_session || rs.empty()) {
6475 RegionView* rv = rs.front();
6477 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6481 Editor::use_range_as_bar ()
6483 framepos_t start, end;
6484 if (get_edit_op_range (start, end)) {
6485 define_one_bar (start, end);
6490 Editor::define_one_bar (framepos_t start, framepos_t end)
6492 framepos_t length = end - start;
6494 const Meter& m (_session->tempo_map().meter_at_frame (start));
6496 /* length = 1 bar */
6498 /* We're going to deliver a constant tempo here,
6499 so we can use frames per beat to determine length.
6500 now we want frames per beat.
6501 we have frames per bar, and beats per bar, so ...
6504 /* XXXX METER MATH */
6506 double frames_per_beat = length / m.divisions_per_bar();
6508 /* beats per minute = */
6510 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6512 /* now decide whether to:
6514 (a) set global tempo
6515 (b) add a new tempo marker
6519 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6521 bool do_global = false;
6523 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6525 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6526 at the start, or create a new marker
6529 vector<string> options;
6530 options.push_back (_("Cancel"));
6531 options.push_back (_("Add new marker"));
6532 options.push_back (_("Set global tempo"));
6535 _("Define one bar"),
6536 _("Do you want to set the global tempo or add a new tempo marker?"),
6540 c.set_default_response (2);
6556 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6557 if the marker is at the region starter, change it, otherwise add
6562 begin_reversible_command (_("set tempo from region"));
6563 XMLNode& before (_session->tempo_map().get_state());
6566 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6567 } else if (t.frame() == start) {
6568 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6570 const Tempo tempo (beats_per_minute, t.note_type());
6571 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6574 XMLNode& after (_session->tempo_map().get_state());
6576 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6577 commit_reversible_command ();
6581 Editor::split_region_at_transients ()
6583 AnalysisFeatureList positions;
6585 RegionSelection rs = get_regions_from_selection_and_entered ();
6587 if (!_session || rs.empty()) {
6591 begin_reversible_command (_("split regions"));
6593 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6595 RegionSelection::iterator tmp;
6600 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6603 ar->transients (positions);
6604 split_region_at_points ((*i)->region(), positions, true);
6611 commit_reversible_command ();
6616 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6618 bool use_rhythmic_rodent = false;
6620 boost::shared_ptr<Playlist> pl = r->playlist();
6622 list<boost::shared_ptr<Region> > new_regions;
6628 if (positions.empty()) {
6632 if (positions.size() > 20 && can_ferret) {
6633 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);
6634 MessageDialog msg (msgstr,
6637 Gtk::BUTTONS_OK_CANCEL);
6640 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6641 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6643 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6646 msg.set_title (_("Excessive split?"));
6649 int response = msg.run();
6655 case RESPONSE_APPLY:
6656 use_rhythmic_rodent = true;
6663 if (use_rhythmic_rodent) {
6664 show_rhythm_ferret ();
6668 AnalysisFeatureList::const_iterator x;
6670 pl->clear_changes ();
6671 pl->clear_owned_changes ();
6673 x = positions.begin();
6675 if (x == positions.end()) {
6680 pl->remove_region (r);
6684 framepos_t rstart = r->first_frame ();
6685 framepos_t rend = r->last_frame ();
6687 while (x != positions.end()) {
6689 /* deal with positons that are out of scope of present region bounds */
6690 if (*x <= rstart || *x > rend) {
6695 /* file start = original start + how far we from the initial position ? */
6697 framepos_t file_start = r->start() + pos;
6699 /* length = next position - current position */
6701 framepos_t len = (*x) - pos - rstart;
6703 /* XXX we do we really want to allow even single-sample regions?
6704 * shouldn't we have some kind of lower limit on region size?
6713 if (RegionFactory::region_name (new_name, r->name())) {
6717 /* do NOT announce new regions 1 by one, just wait till they are all done */
6721 plist.add (ARDOUR::Properties::start, file_start);
6722 plist.add (ARDOUR::Properties::length, len);
6723 plist.add (ARDOUR::Properties::name, new_name);
6724 plist.add (ARDOUR::Properties::layer, 0);
6725 // TODO set transients_offset
6727 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6728 /* because we set annouce to false, manually add the new region to the
6731 RegionFactory::map_add (nr);
6733 pl->add_region (nr, rstart + pos);
6736 new_regions.push_front(nr);
6745 RegionFactory::region_name (new_name, r->name());
6747 /* Add the final region */
6750 plist.add (ARDOUR::Properties::start, r->start() + pos);
6751 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6752 plist.add (ARDOUR::Properties::name, new_name);
6753 plist.add (ARDOUR::Properties::layer, 0);
6755 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6756 /* because we set annouce to false, manually add the new region to the
6759 RegionFactory::map_add (nr);
6760 pl->add_region (nr, r->position() + pos);
6763 new_regions.push_front(nr);
6768 /* We might have removed regions, which alters other regions' layering_index,
6769 so we need to do a recursive diff here.
6771 vector<Command*> cmds;
6773 _session->add_commands (cmds);
6775 _session->add_command (new StatefulDiffCommand (pl));
6779 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6780 set_selected_regionview_from_region_list ((*i), Selection::Add);
6786 Editor::place_transient()
6792 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6798 framepos_t where = get_preferred_edit_position();
6800 begin_reversible_command (_("place transient"));
6802 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6803 (*r)->region()->add_transient(where);
6806 commit_reversible_command ();
6810 Editor::remove_transient(ArdourCanvas::Item* item)
6816 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6819 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6820 _arv->remove_transient (*(float*) _line->get_data ("position"));
6824 Editor::snap_regions_to_grid ()
6826 list <boost::shared_ptr<Playlist > > used_playlists;
6828 RegionSelection rs = get_regions_from_selection_and_entered ();
6830 if (!_session || rs.empty()) {
6834 begin_reversible_command (_("snap regions to grid"));
6836 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6838 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6840 if (!pl->frozen()) {
6841 /* we haven't seen this playlist before */
6843 /* remember used playlists so we can thaw them later */
6844 used_playlists.push_back(pl);
6848 framepos_t start_frame = (*r)->region()->first_frame ();
6849 snap_to (start_frame);
6850 (*r)->region()->set_position (start_frame);
6853 while (used_playlists.size() > 0) {
6854 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6856 used_playlists.pop_front();
6859 commit_reversible_command ();
6863 Editor::close_region_gaps ()
6865 list <boost::shared_ptr<Playlist > > used_playlists;
6867 RegionSelection rs = get_regions_from_selection_and_entered ();
6869 if (!_session || rs.empty()) {
6873 Dialog dialog (_("Close Region Gaps"));
6876 table.set_spacings (12);
6877 table.set_border_width (12);
6878 Label* l = manage (left_aligned_label (_("Crossfade length")));
6879 table.attach (*l, 0, 1, 0, 1);
6881 SpinButton spin_crossfade (1, 0);
6882 spin_crossfade.set_range (0, 15);
6883 spin_crossfade.set_increments (1, 1);
6884 spin_crossfade.set_value (5);
6885 table.attach (spin_crossfade, 1, 2, 0, 1);
6887 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6889 l = manage (left_aligned_label (_("Pull-back length")));
6890 table.attach (*l, 0, 1, 1, 2);
6892 SpinButton spin_pullback (1, 0);
6893 spin_pullback.set_range (0, 100);
6894 spin_pullback.set_increments (1, 1);
6895 spin_pullback.set_value(30);
6896 table.attach (spin_pullback, 1, 2, 1, 2);
6898 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6900 dialog.get_vbox()->pack_start (table);
6901 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6902 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6905 if (dialog.run () == RESPONSE_CANCEL) {
6909 framepos_t crossfade_len = spin_crossfade.get_value();
6910 framepos_t pull_back_frames = spin_pullback.get_value();
6912 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6913 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6915 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6917 begin_reversible_command (_("close region gaps"));
6920 boost::shared_ptr<Region> last_region;
6922 rs.sort_by_position_and_track();
6924 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6926 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6928 if (!pl->frozen()) {
6929 /* we haven't seen this playlist before */
6931 /* remember used playlists so we can thaw them later */
6932 used_playlists.push_back(pl);
6936 framepos_t position = (*r)->region()->position();
6938 if (idx == 0 || position < last_region->position()){
6939 last_region = (*r)->region();
6944 (*r)->region()->trim_front( (position - pull_back_frames));
6945 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6947 last_region = (*r)->region();
6952 while (used_playlists.size() > 0) {
6953 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6955 used_playlists.pop_front();
6958 commit_reversible_command ();
6962 Editor::tab_to_transient (bool forward)
6964 AnalysisFeatureList positions;
6966 RegionSelection rs = get_regions_from_selection_and_entered ();
6972 framepos_t pos = _session->audible_frame ();
6974 if (!selection->tracks.empty()) {
6976 /* don't waste time searching for transients in duplicate playlists.
6979 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6981 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6983 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6986 boost::shared_ptr<Track> tr = rtv->track();
6988 boost::shared_ptr<Playlist> pl = tr->playlist ();
6990 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6993 positions.push_back (result);
7006 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7007 (*r)->region()->get_transients (positions);
7011 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7014 AnalysisFeatureList::iterator x;
7016 for (x = positions.begin(); x != positions.end(); ++x) {
7022 if (x != positions.end ()) {
7023 _session->request_locate (*x);
7027 AnalysisFeatureList::reverse_iterator x;
7029 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7035 if (x != positions.rend ()) {
7036 _session->request_locate (*x);
7042 Editor::playhead_forward_to_grid ()
7048 framepos_t pos = playhead_cursor->current_frame ();
7049 if (pos < max_framepos - 1) {
7051 snap_to_internal (pos, RoundUpAlways, false);
7052 _session->request_locate (pos);
7058 Editor::playhead_backward_to_grid ()
7064 framepos_t pos = playhead_cursor->current_frame ();
7067 snap_to_internal (pos, RoundDownAlways, false);
7068 _session->request_locate (pos);
7073 Editor::set_track_height (Height h)
7075 TrackSelection& ts (selection->tracks);
7077 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7078 (*x)->set_height_enum (h);
7083 Editor::toggle_tracks_active ()
7085 TrackSelection& ts (selection->tracks);
7087 bool target = false;
7093 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7094 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7098 target = !rtv->_route->active();
7101 rtv->_route->set_active (target, this);
7107 Editor::remove_tracks ()
7109 /* this will delete GUI objects that may be the subject of an event
7110 handler in which this method is called. Defer actual deletion to the
7111 next idle callback, when all event handling is finished.
7113 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7117 Editor::idle_remove_tracks ()
7119 Session::StateProtector sp (_session);
7121 return false; /* do not call again */
7125 Editor::_remove_tracks ()
7127 TrackSelection& ts (selection->tracks);
7133 vector<string> choices;
7137 const char* trackstr;
7139 vector<boost::shared_ptr<Route> > routes;
7140 bool special_bus = false;
7142 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7143 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7147 if (rtv->is_track()) {
7152 routes.push_back (rtv->_route);
7154 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7159 if (special_bus && !Config->get_allow_special_bus_removal()) {
7160 MessageDialog msg (_("That would be bad news ...."),
7164 msg.set_secondary_text (string_compose (_(
7165 "Removing the master or monitor bus is such a bad idea\n\
7166 that %1 is not going to allow it.\n\
7168 If you really want to do this sort of thing\n\
7169 edit your ardour.rc file to set the\n\
7170 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7177 if (ntracks + nbusses == 0) {
7181 trackstr = P_("track", "tracks", ntracks);
7182 busstr = P_("bus", "busses", nbusses);
7186 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7187 "(You may also lose the playlists associated with the %2)\n\n"
7188 "This action cannot be undone, and the session file will be overwritten!"),
7189 ntracks, trackstr, nbusses, busstr);
7191 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7192 "(You may also lose the playlists associated with the %2)\n\n"
7193 "This action cannot be undone, and the session file will be overwritten!"),
7196 } else if (nbusses) {
7197 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7198 "This action cannot be undone, and the session file will be overwritten"),
7202 choices.push_back (_("No, do nothing."));
7203 if (ntracks + nbusses > 1) {
7204 choices.push_back (_("Yes, remove them."));
7206 choices.push_back (_("Yes, remove it."));
7211 title = string_compose (_("Remove %1"), trackstr);
7213 title = string_compose (_("Remove %1"), busstr);
7216 Choice prompter (title, prompt, choices);
7218 if (prompter.run () != 1) {
7223 DisplaySuspender ds;
7224 boost::shared_ptr<RouteList> rl (new RouteList);
7225 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7228 _session->remove_routes (rl);
7230 /* TrackSelection and RouteList leave scope,
7231 * destructors are called,
7232 * diskstream drops references, save_state is called (again for every track)
7237 Editor::do_insert_time ()
7239 if (selection->tracks.empty()) {
7243 InsertRemoveTimeDialog d (*this);
7244 int response = d.run ();
7246 if (response != RESPONSE_OK) {
7250 if (d.distance() == 0) {
7255 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7257 d.intersected_region_action (),
7261 d.move_glued_markers(),
7262 d.move_locked_markers(),
7268 Editor::insert_time (
7269 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7270 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7274 if (Config->get_edit_mode() == Lock) {
7277 bool in_command = false;
7279 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7281 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7285 /* don't operate on any playlist more than once, which could
7286 * happen if "all playlists" is enabled, but there is more
7287 * than 1 track using playlists "from" a given track.
7290 set<boost::shared_ptr<Playlist> > pl;
7292 if (all_playlists) {
7293 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7294 if (rtav && rtav->track ()) {
7295 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7296 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7301 if ((*x)->playlist ()) {
7302 pl.insert ((*x)->playlist ());
7306 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7308 (*i)->clear_changes ();
7309 (*i)->clear_owned_changes ();
7311 if (opt == SplitIntersected) {
7312 /* non musical split */
7313 (*i)->split (pos, 0);
7316 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7319 begin_reversible_command (_("insert time"));
7322 vector<Command*> cmds;
7324 _session->add_commands (cmds);
7326 _session->add_command (new StatefulDiffCommand (*i));
7330 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7333 begin_reversible_command (_("insert time"));
7336 rtav->route ()->shift (pos, frames);
7343 XMLNode& before (_session->locations()->get_state());
7344 Locations::LocationList copy (_session->locations()->list());
7346 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7348 Locations::LocationList::const_iterator tmp;
7350 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7351 bool const was_locked = (*i)->locked ();
7352 if (locked_markers_too) {
7356 if ((*i)->start() >= pos) {
7357 // move end first, in case we're moving by more than the length of the range
7358 if (!(*i)->is_mark()) {
7359 (*i)->set_end ((*i)->end() + frames);
7361 (*i)->set_start ((*i)->start() + frames);
7373 begin_reversible_command (_("insert time"));
7376 XMLNode& after (_session->locations()->get_state());
7377 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7383 begin_reversible_command (_("insert time"));
7386 XMLNode& before (_session->tempo_map().get_state());
7387 _session->tempo_map().insert_time (pos, frames);
7388 XMLNode& after (_session->tempo_map().get_state());
7389 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7393 commit_reversible_command ();
7398 Editor::do_remove_time ()
7400 if (selection->tracks.empty()) {
7404 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7405 InsertRemoveTimeDialog d (*this, true);
7407 int response = d.run ();
7409 if (response != RESPONSE_OK) {
7413 framecnt_t distance = d.distance();
7415 if (distance == 0) {
7425 d.move_glued_markers(),
7426 d.move_locked_markers(),
7432 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7433 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7435 if (Config->get_edit_mode() == Lock) {
7436 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7439 bool in_command = false;
7441 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7443 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7447 XMLNode &before = pl->get_state();
7449 std::list<AudioRange> rl;
7450 AudioRange ar(pos, pos+frames, 0);
7453 pl->shift (pos, -frames, true, ignore_music_glue);
7456 begin_reversible_command (_("remove time"));
7459 XMLNode &after = pl->get_state();
7461 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7465 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7468 begin_reversible_command (_("remove time"));
7471 rtav->route ()->shift (pos, -frames);
7475 std::list<Location*> loc_kill_list;
7480 XMLNode& before (_session->locations()->get_state());
7481 Locations::LocationList copy (_session->locations()->list());
7483 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7484 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7486 bool const was_locked = (*i)->locked ();
7487 if (locked_markers_too) {
7491 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7492 if ((*i)->end() >= pos
7493 && (*i)->end() < pos+frames
7494 && (*i)->start() >= pos
7495 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7497 loc_kill_list.push_back(*i);
7498 } else { // only start or end is included, try to do the right thing
7499 // move start before moving end, to avoid trying to move the end to before the start
7500 // if we're removing more time than the length of the range
7501 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7502 // start is within cut
7503 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7505 } else if ((*i)->start() >= pos+frames) {
7506 // start (and thus entire range) lies beyond end of cut
7507 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7510 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7511 // end is inside cut
7512 (*i)->set_end (pos); // bring the end to the cut
7514 } else if ((*i)->end() >= pos+frames) {
7515 // end is beyond end of cut
7516 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7521 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7522 loc_kill_list.push_back(*i);
7524 } else if ((*i)->start() >= pos) {
7525 (*i)->set_start ((*i)->start() -frames);
7535 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7536 _session->locations()->remove( *i );
7541 begin_reversible_command (_("remove time"));
7544 XMLNode& after (_session->locations()->get_state());
7545 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7550 XMLNode& before (_session->tempo_map().get_state());
7552 if (_session->tempo_map().remove_time (pos, frames) ) {
7554 begin_reversible_command (_("remove time"));
7557 XMLNode& after (_session->tempo_map().get_state());
7558 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7563 commit_reversible_command ();
7568 Editor::fit_selection ()
7570 if (!selection->tracks.empty()) {
7571 fit_tracks (selection->tracks);
7575 /* no selected tracks - use tracks with selected regions */
7577 if (!selection->regions.empty()) {
7578 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7579 tvl.push_back (&(*r)->get_time_axis_view ());
7585 } else if (internal_editing()) {
7586 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7589 if (entered_track) {
7590 tvl.push_back (entered_track);
7599 Editor::fit_tracks (TrackViewList & tracks)
7601 if (tracks.empty()) {
7605 uint32_t child_heights = 0;
7606 int visible_tracks = 0;
7608 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7610 if (!(*t)->marked_for_display()) {
7614 child_heights += (*t)->effective_height() - (*t)->current_height();
7618 /* compute the per-track height from:
7620 total canvas visible height -
7621 height that will be taken by visible children of selected
7622 tracks - height of the ruler/hscroll area
7624 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7625 double first_y_pos = DBL_MAX;
7627 if (h < TimeAxisView::preset_height (HeightSmall)) {
7628 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7629 /* too small to be displayed */
7633 undo_visual_stack.push_back (current_visual_state (true));
7634 PBD::Unwinder<bool> nsv (no_save_visual, true);
7636 /* build a list of all tracks, including children */
7639 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7641 TimeAxisView::Children c = (*i)->get_child_list ();
7642 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7643 all.push_back (j->get());
7648 // find selection range.
7649 // if someone knows how to user TrackViewList::iterator for this
7651 int selected_top = -1;
7652 int selected_bottom = -1;
7654 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7655 if ((*t)->marked_for_display ()) {
7656 if (tracks.contains(*t)) {
7657 if (selected_top == -1) {
7660 selected_bottom = i;
7666 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7667 if ((*t)->marked_for_display ()) {
7668 if (tracks.contains(*t)) {
7669 (*t)->set_height (h);
7670 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7672 if (i > selected_top && i < selected_bottom) {
7673 hide_track_in_display (*t);
7680 set the controls_layout height now, because waiting for its size
7681 request signal handler will cause the vertical adjustment setting to fail
7684 controls_layout.property_height () = _full_canvas_height;
7685 vertical_adjustment.set_value (first_y_pos);
7687 redo_visual_stack.push_back (current_visual_state (true));
7689 visible_tracks_selector.set_text (_("Sel"));
7693 Editor::save_visual_state (uint32_t n)
7695 while (visual_states.size() <= n) {
7696 visual_states.push_back (0);
7699 if (visual_states[n] != 0) {
7700 delete visual_states[n];
7703 visual_states[n] = current_visual_state (true);
7708 Editor::goto_visual_state (uint32_t n)
7710 if (visual_states.size() <= n) {
7714 if (visual_states[n] == 0) {
7718 use_visual_state (*visual_states[n]);
7722 Editor::start_visual_state_op (uint32_t n)
7724 save_visual_state (n);
7726 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7728 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7729 pup->set_text (buf);
7734 Editor::cancel_visual_state_op (uint32_t n)
7736 goto_visual_state (n);
7740 Editor::toggle_region_mute ()
7742 if (_ignore_region_action) {
7746 RegionSelection rs = get_regions_from_selection_and_entered ();
7752 if (rs.size() > 1) {
7753 begin_reversible_command (_("mute regions"));
7755 begin_reversible_command (_("mute region"));
7758 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7760 (*i)->region()->playlist()->clear_changes ();
7761 (*i)->region()->set_muted (!(*i)->region()->muted ());
7762 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7766 commit_reversible_command ();
7770 Editor::combine_regions ()
7772 /* foreach track with selected regions, take all selected regions
7773 and join them into a new region containing the subregions (as a
7777 typedef set<RouteTimeAxisView*> RTVS;
7780 if (selection->regions.empty()) {
7784 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7785 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7788 tracks.insert (rtv);
7792 begin_reversible_command (_("combine regions"));
7794 vector<RegionView*> new_selection;
7796 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7799 if ((rv = (*i)->combine_regions ()) != 0) {
7800 new_selection.push_back (rv);
7804 selection->clear_regions ();
7805 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7806 selection->add (*i);
7809 commit_reversible_command ();
7813 Editor::uncombine_regions ()
7815 typedef set<RouteTimeAxisView*> RTVS;
7818 if (selection->regions.empty()) {
7822 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7823 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7826 tracks.insert (rtv);
7830 begin_reversible_command (_("uncombine regions"));
7832 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7833 (*i)->uncombine_regions ();
7836 commit_reversible_command ();
7840 Editor::toggle_midi_input_active (bool flip_others)
7843 boost::shared_ptr<RouteList> rl (new RouteList);
7845 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7846 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7852 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7855 rl->push_back (rtav->route());
7856 onoff = !mt->input_active();
7860 _session->set_exclusive_input_active (rl, onoff, flip_others);
7867 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7869 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7870 lock_dialog->get_vbox()->pack_start (*padlock);
7872 ArdourButton* b = manage (new ArdourButton);
7873 b->set_name ("lock button");
7874 b->set_text (_("Click to unlock"));
7875 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7876 lock_dialog->get_vbox()->pack_start (*b);
7878 lock_dialog->get_vbox()->show_all ();
7879 lock_dialog->set_size_request (200, 200);
7882 delete _main_menu_disabler;
7883 _main_menu_disabler = new MainMenuDisabler;
7885 lock_dialog->present ();
7891 lock_dialog->hide ();
7893 delete _main_menu_disabler;
7894 _main_menu_disabler = 0;
7896 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7897 start_lock_event_timing ();
7902 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7904 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7908 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7910 Timers::TimerSuspender t;
7911 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7912 Gtkmm2ext::UI::instance()->flush_pending ();
7916 Editor::bring_all_sources_into_session ()
7923 ArdourDialog w (_("Moving embedded files into session folder"));
7924 w.get_vbox()->pack_start (msg);
7927 /* flush all pending GUI events because we're about to start copying
7931 Timers::TimerSuspender t;
7932 Gtkmm2ext::UI::instance()->flush_pending ();
7936 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));