2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "audio_region_view.h"
65 #include "audio_streamview.h"
66 #include "audio_time_axis.h"
67 #include "automation_region_view.h"
68 #include "automation_time_axis.h"
69 #include "control_point.h"
73 #include "editor_cursors.h"
74 #include "editor_drag.h"
75 #include "editor_regions.h"
76 #include "editor_routes.h"
77 #include "gui_thread.h"
78 #include "insert_remove_time_dialog.h"
79 #include "interthread_progress_window.h"
80 #include "item_counts.h"
82 #include "midi_region_view.h"
83 #include "mixer_strip.h"
84 #include "mouse_cursors.h"
85 #include "normalize_dialog.h"
87 #include "paste_context.h"
88 #include "patch_change_dialog.h"
89 #include "quantize_dialog.h"
90 #include "region_gain_line.h"
91 #include "rgb_macros.h"
92 #include "route_time_axis.h"
93 #include "selection.h"
94 #include "selection_templates.h"
95 #include "streamview.h"
96 #include "strip_silence_dialog.h"
97 #include "time_axis_view.h"
98 #include "transpose_dialog.h"
99 #include "transform_dialog.h"
100 #include "ui_config.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
112 /***********************************************************************
114 ***********************************************************************/
117 Editor::undo (uint32_t n)
119 if (_drags->active ()) {
125 if (_session->undo_depth() == 0) {
126 undo_action->set_sensitive(false);
128 redo_action->set_sensitive(true);
129 begin_selection_op_history ();
134 Editor::redo (uint32_t n)
136 if (_drags->active ()) {
142 if (_session->redo_depth() == 0) {
143 redo_action->set_sensitive(false);
145 undo_action->set_sensitive(true);
146 begin_selection_op_history ();
151 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
155 RegionSelection pre_selected_regions = selection->regions;
156 bool working_on_selection = !pre_selected_regions.empty();
158 list<boost::shared_ptr<Playlist> > used_playlists;
159 list<RouteTimeAxisView*> used_trackviews;
161 if (regions.empty()) {
165 begin_reversible_command (_("split"));
167 // if splitting a single region, and snap-to is using
168 // region boundaries, don't pay attention to them
170 if (regions.size() == 1) {
171 switch (_snap_type) {
172 case SnapToRegionStart:
173 case SnapToRegionSync:
174 case SnapToRegionEnd:
183 EditorFreeze(); /* Emit Signal */
186 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
188 RegionSelection::iterator tmp;
190 /* XXX this test needs to be more complicated, to make sure we really
191 have something to split.
194 if (!(*a)->region()->covers (where)) {
202 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
210 /* we haven't seen this playlist before */
212 /* remember used playlists so we can thaw them later */
213 used_playlists.push_back(pl);
215 TimeAxisView& tv = (*a)->get_time_axis_view();
216 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
218 used_trackviews.push_back (rtv);
225 pl->clear_changes ();
226 pl->split_region ((*a)->region(), where);
227 _session->add_command (new StatefulDiffCommand (pl));
233 latest_regionviews.clear ();
235 vector<sigc::connection> region_added_connections;
237 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
238 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
241 while (used_playlists.size() > 0) {
242 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
244 used_playlists.pop_front();
247 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
252 EditorThaw(); /* Emit Signal */
255 if (working_on_selection) {
256 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
258 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
259 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
260 /* There are three classes of regions that we might want selected after
261 splitting selected regions:
262 - regions selected before the split operation, and unaffected by it
263 - newly-created regions before the split
264 - newly-created regions after the split
267 if (rsas & Existing) {
268 // region selections that existed before the split.
269 selection->add ( pre_selected_regions );
272 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
273 if ((*ri)->region()->position() < where) {
274 // new regions created before the split
275 if (rsas & NewlyCreatedLeft) {
276 selection->add (*ri);
279 // new regions created after the split
280 if (rsas & NewlyCreatedRight) {
281 selection->add (*ri);
285 _ignore_follow_edits = false;
287 _ignore_follow_edits = true;
288 if( working_on_selection ) {
289 selection->add (latest_regionviews); //these are the new regions created after the split
291 _ignore_follow_edits = false;
294 commit_reversible_command ();
297 /** Move one extreme of the current range selection. If more than one range is selected,
298 * the start of the earliest range or the end of the latest range is moved.
300 * @param move_end true to move the end of the current range selection, false to move
302 * @param next true to move the extreme to the next region boundary, false to move to
306 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
308 if (selection->time.start() == selection->time.end_frame()) {
312 framepos_t start = selection->time.start ();
313 framepos_t end = selection->time.end_frame ();
315 /* the position of the thing we may move */
316 framepos_t pos = move_end ? end : start;
317 int dir = next ? 1 : -1;
319 /* so we don't find the current region again */
320 if (dir > 0 || pos > 0) {
324 framepos_t const target = get_region_boundary (pos, dir, true, false);
339 begin_reversible_selection_op (_("alter selection"));
340 selection->set_preserving_all_ranges (start, end);
341 commit_reversible_selection_op ();
345 Editor::nudge_forward_release (GdkEventButton* ev)
347 if (ev->state & Keyboard::PrimaryModifier) {
348 nudge_forward (false, true);
350 nudge_forward (false, false);
356 Editor::nudge_backward_release (GdkEventButton* ev)
358 if (ev->state & Keyboard::PrimaryModifier) {
359 nudge_backward (false, true);
361 nudge_backward (false, false);
368 Editor::nudge_forward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions forward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
393 r->set_position (r->position() + distance);
394 _session->add_command (new StatefulDiffCommand (r));
397 commit_reversible_command ();
400 } else if (!force_playhead && !selection->markers.empty()) {
403 bool in_command = false;
405 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
407 Location* loc = find_location_from_marker ((*i), is_start);
411 XMLNode& before (loc->get_state());
414 distance = get_nudge_distance (loc->start(), next_distance);
416 distance = next_distance;
418 if (max_framepos - distance > loc->start() + loc->length()) {
419 loc->set_start (loc->start() + distance);
421 loc->set_start (max_framepos - loc->length());
424 distance = get_nudge_distance (loc->end(), next_distance);
426 distance = next_distance;
428 if (max_framepos - distance > loc->end()) {
429 loc->set_end (loc->end() + distance);
431 loc->set_end (max_framepos);
435 begin_reversible_command (_("nudge location forward"));
438 XMLNode& after (loc->get_state());
439 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
444 commit_reversible_command ();
447 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
448 _session->request_locate (playhead_cursor->current_frame () + distance);
453 Editor::nudge_backward (bool next, bool force_playhead)
456 framepos_t next_distance;
462 RegionSelection rs = get_regions_from_selection_and_entered ();
464 if (!force_playhead && !rs.empty()) {
466 begin_reversible_command (_("nudge regions backward"));
468 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
469 boost::shared_ptr<Region> r ((*i)->region());
471 distance = get_nudge_distance (r->position(), next_distance);
474 distance = next_distance;
479 if (r->position() > distance) {
480 r->set_position (r->position() - distance);
484 _session->add_command (new StatefulDiffCommand (r));
487 commit_reversible_command ();
489 } else if (!force_playhead && !selection->markers.empty()) {
492 bool in_command = false;
494 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
496 Location* loc = find_location_from_marker ((*i), is_start);
500 XMLNode& before (loc->get_state());
503 distance = get_nudge_distance (loc->start(), next_distance);
505 distance = next_distance;
507 if (distance < loc->start()) {
508 loc->set_start (loc->start() - distance);
513 distance = get_nudge_distance (loc->end(), next_distance);
516 distance = next_distance;
519 if (distance < loc->end() - loc->length()) {
520 loc->set_end (loc->end() - distance);
522 loc->set_end (loc->length());
526 begin_reversible_command (_("nudge location forward"));
529 XMLNode& after (loc->get_state());
530 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
534 commit_reversible_command ();
539 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
541 if (playhead_cursor->current_frame () > distance) {
542 _session->request_locate (playhead_cursor->current_frame () - distance);
544 _session->goto_start();
550 Editor::nudge_forward_capture_offset ()
552 RegionSelection rs = get_regions_from_selection_and_entered ();
554 if (!_session || rs.empty()) {
558 begin_reversible_command (_("nudge forward"));
560 framepos_t const distance = _session->worst_output_latency();
562 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
563 boost::shared_ptr<Region> r ((*i)->region());
566 r->set_position (r->position() + distance);
567 _session->add_command(new StatefulDiffCommand (r));
570 commit_reversible_command ();
574 Editor::nudge_backward_capture_offset ()
576 RegionSelection rs = get_regions_from_selection_and_entered ();
578 if (!_session || rs.empty()) {
582 begin_reversible_command (_("nudge backward"));
584 framepos_t const distance = _session->worst_output_latency();
586 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
587 boost::shared_ptr<Region> r ((*i)->region());
591 if (r->position() > distance) {
592 r->set_position (r->position() - distance);
596 _session->add_command(new StatefulDiffCommand (r));
599 commit_reversible_command ();
602 struct RegionSelectionPositionSorter {
603 bool operator() (RegionView* a, RegionView* b) {
604 return a->region()->position() < b->region()->position();
609 Editor::sequence_regions ()
612 framepos_t r_end_prev;
620 RegionSelection rs = get_regions_from_selection_and_entered ();
621 rs.sort(RegionSelectionPositionSorter());
625 bool in_command = false;
627 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
628 boost::shared_ptr<Region> r ((*i)->region());
636 if(r->position_locked())
643 r->set_position(r_end_prev);
647 begin_reversible_command (_("sequence regions"));
650 _session->add_command (new StatefulDiffCommand (r));
652 r_end=r->position() + r->length();
658 commit_reversible_command ();
667 Editor::move_to_start ()
669 _session->goto_start ();
673 Editor::move_to_end ()
676 _session->request_locate (_session->current_end_frame());
680 Editor::build_region_boundary_cache ()
683 vector<RegionPoint> interesting_points;
684 boost::shared_ptr<Region> r;
685 TrackViewList tracks;
688 region_boundary_cache.clear ();
694 switch (_snap_type) {
695 case SnapToRegionStart:
696 interesting_points.push_back (Start);
698 case SnapToRegionEnd:
699 interesting_points.push_back (End);
701 case SnapToRegionSync:
702 interesting_points.push_back (SyncPoint);
704 case SnapToRegionBoundary:
705 interesting_points.push_back (Start);
706 interesting_points.push_back (End);
709 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
710 abort(); /*NOTREACHED*/
714 TimeAxisView *ontrack = 0;
717 if (!selection->tracks.empty()) {
718 tlist = selection->tracks.filter_to_unique_playlists ();
720 tlist = track_views.filter_to_unique_playlists ();
723 while (pos < _session->current_end_frame() && !at_end) {
726 framepos_t lpos = max_framepos;
728 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
730 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
731 if (*p == interesting_points.back()) {
734 /* move to next point type */
740 rpos = r->first_frame();
744 rpos = r->last_frame();
748 rpos = r->sync_position ();
756 RouteTimeAxisView *rtav;
758 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
759 if (rtav->track() != 0) {
760 speed = rtav->track()->speed();
764 rpos = track_frame_to_session_frame (rpos, speed);
770 /* prevent duplicates, but we don't use set<> because we want to be able
774 vector<framepos_t>::iterator ri;
776 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
782 if (ri == region_boundary_cache.end()) {
783 region_boundary_cache.push_back (rpos);
790 /* finally sort to be sure that the order is correct */
792 sort (region_boundary_cache.begin(), region_boundary_cache.end());
795 boost::shared_ptr<Region>
796 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
798 TrackViewList::iterator i;
799 framepos_t closest = max_framepos;
800 boost::shared_ptr<Region> ret;
804 framepos_t track_frame;
805 RouteTimeAxisView *rtav;
807 for (i = tracks.begin(); i != tracks.end(); ++i) {
810 boost::shared_ptr<Region> r;
813 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
814 if (rtav->track()!=0)
815 track_speed = rtav->track()->speed();
818 track_frame = session_frame_to_track_frame(frame, track_speed);
820 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
826 rpos = r->first_frame ();
830 rpos = r->last_frame ();
834 rpos = r->sync_position ();
838 // rpos is a "track frame", converting it to "_session frame"
839 rpos = track_frame_to_session_frame(rpos, track_speed);
842 distance = rpos - frame;
844 distance = frame - rpos;
847 if (distance < closest) {
859 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
861 framecnt_t distance = max_framepos;
862 framepos_t current_nearest = -1;
864 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
865 framepos_t contender;
868 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
874 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
878 d = ::llabs (pos - contender);
881 current_nearest = contender;
886 return current_nearest;
890 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
895 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
897 if (!selection->tracks.empty()) {
899 target = find_next_region_boundary (pos, dir, selection->tracks);
903 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
904 get_onscreen_tracks (tvl);
905 target = find_next_region_boundary (pos, dir, tvl);
907 target = find_next_region_boundary (pos, dir, track_views);
913 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
914 get_onscreen_tracks (tvl);
915 target = find_next_region_boundary (pos, dir, tvl);
917 target = find_next_region_boundary (pos, dir, track_views);
925 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
927 framepos_t pos = playhead_cursor->current_frame ();
934 // so we don't find the current region again..
935 if (dir > 0 || pos > 0) {
939 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
943 _session->request_locate (target);
947 Editor::cursor_to_next_region_boundary (bool with_selection)
949 cursor_to_region_boundary (with_selection, 1);
953 Editor::cursor_to_previous_region_boundary (bool with_selection)
955 cursor_to_region_boundary (with_selection, -1);
959 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
961 boost::shared_ptr<Region> r;
962 framepos_t pos = cursor->current_frame ();
968 TimeAxisView *ontrack = 0;
970 // so we don't find the current region again..
974 if (!selection->tracks.empty()) {
976 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
978 } else if (clicked_axisview) {
981 t.push_back (clicked_axisview);
983 r = find_next_region (pos, point, dir, t, &ontrack);
987 r = find_next_region (pos, point, dir, track_views, &ontrack);
996 pos = r->first_frame ();
1000 pos = r->last_frame ();
1004 pos = r->sync_position ();
1009 RouteTimeAxisView *rtav;
1011 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1012 if (rtav->track() != 0) {
1013 speed = rtav->track()->speed();
1017 pos = track_frame_to_session_frame(pos, speed);
1019 if (cursor == playhead_cursor) {
1020 _session->request_locate (pos);
1022 cursor->set_position (pos);
1027 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1029 cursor_to_region_point (cursor, point, 1);
1033 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1035 cursor_to_region_point (cursor, point, -1);
1039 Editor::cursor_to_selection_start (EditorCursor *cursor)
1043 switch (mouse_mode) {
1045 if (!selection->regions.empty()) {
1046 pos = selection->regions.start();
1051 if (!selection->time.empty()) {
1052 pos = selection->time.start ();
1060 if (cursor == playhead_cursor) {
1061 _session->request_locate (pos);
1063 cursor->set_position (pos);
1068 Editor::cursor_to_selection_end (EditorCursor *cursor)
1072 switch (mouse_mode) {
1074 if (!selection->regions.empty()) {
1075 pos = selection->regions.end_frame();
1080 if (!selection->time.empty()) {
1081 pos = selection->time.end_frame ();
1089 if (cursor == playhead_cursor) {
1090 _session->request_locate (pos);
1092 cursor->set_position (pos);
1097 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1107 if (selection->markers.empty()) {
1111 if (!mouse_frame (mouse, ignored)) {
1115 add_location_mark (mouse);
1118 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1122 framepos_t pos = loc->start();
1124 // so we don't find the current region again..
1125 if (dir > 0 || pos > 0) {
1129 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1133 loc->move_to (target);
1137 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1139 selected_marker_to_region_boundary (with_selection, 1);
1143 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1145 selected_marker_to_region_boundary (with_selection, -1);
1149 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1151 boost::shared_ptr<Region> r;
1156 if (!_session || selection->markers.empty()) {
1160 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1164 TimeAxisView *ontrack = 0;
1168 // so we don't find the current region again..
1172 if (!selection->tracks.empty()) {
1174 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1178 r = find_next_region (pos, point, dir, track_views, &ontrack);
1187 pos = r->first_frame ();
1191 pos = r->last_frame ();
1195 pos = r->adjust_to_sync (r->first_frame());
1200 RouteTimeAxisView *rtav;
1202 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1203 if (rtav->track() != 0) {
1204 speed = rtav->track()->speed();
1208 pos = track_frame_to_session_frame(pos, speed);
1214 Editor::selected_marker_to_next_region_point (RegionPoint point)
1216 selected_marker_to_region_point (point, 1);
1220 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1222 selected_marker_to_region_point (point, -1);
1226 Editor::selected_marker_to_selection_start ()
1232 if (!_session || selection->markers.empty()) {
1236 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1240 switch (mouse_mode) {
1242 if (!selection->regions.empty()) {
1243 pos = selection->regions.start();
1248 if (!selection->time.empty()) {
1249 pos = selection->time.start ();
1261 Editor::selected_marker_to_selection_end ()
1267 if (!_session || selection->markers.empty()) {
1271 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1275 switch (mouse_mode) {
1277 if (!selection->regions.empty()) {
1278 pos = selection->regions.end_frame();
1283 if (!selection->time.empty()) {
1284 pos = selection->time.end_frame ();
1296 Editor::scroll_playhead (bool forward)
1298 framepos_t pos = playhead_cursor->current_frame ();
1299 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1302 if (pos == max_framepos) {
1306 if (pos < max_framepos - delta) {
1325 _session->request_locate (pos);
1329 Editor::cursor_align (bool playhead_to_edit)
1335 if (playhead_to_edit) {
1337 if (selection->markers.empty()) {
1341 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1344 /* move selected markers to playhead */
1346 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1349 Location* loc = find_location_from_marker (*i, ignored);
1351 if (loc->is_mark()) {
1352 loc->set_start (playhead_cursor->current_frame ());
1354 loc->set (playhead_cursor->current_frame (),
1355 playhead_cursor->current_frame () + loc->length());
1362 Editor::scroll_backward (float pages)
1364 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1365 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1368 if (leftmost_frame < cnt) {
1371 frame = leftmost_frame - cnt;
1374 reset_x_origin (frame);
1378 Editor::scroll_forward (float pages)
1380 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1381 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1384 if (max_framepos - cnt < leftmost_frame) {
1385 frame = max_framepos - cnt;
1387 frame = leftmost_frame + cnt;
1390 reset_x_origin (frame);
1394 Editor::scroll_tracks_down ()
1396 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1397 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1398 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1401 vertical_adjustment.set_value (vert_value);
1405 Editor::scroll_tracks_up ()
1407 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1411 Editor::scroll_tracks_down_line ()
1413 double vert_value = vertical_adjustment.get_value() + 60;
1415 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1416 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1419 vertical_adjustment.set_value (vert_value);
1423 Editor::scroll_tracks_up_line ()
1425 reset_y_origin (vertical_adjustment.get_value() - 60);
1429 Editor::scroll_down_one_track (bool skip_child_views)
1431 TrackViewList::reverse_iterator next = track_views.rend();
1432 const double top_of_trackviews = vertical_adjustment.get_value();
1434 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1435 if ((*t)->hidden()) {
1439 /* If this is the upper-most visible trackview, we want to display
1440 * the one above it (next)
1442 * Note that covers_y_position() is recursive and includes child views
1444 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1447 if (skip_child_views) {
1450 /* automation lane (one level, non-recursive)
1452 * - if no automation lane exists -> move to next tack
1453 * - if the first (here: bottom-most) matches -> move to next tack
1454 * - if no y-axis match is found -> the current track is at the top
1455 * -> move to last (here: top-most) automation lane
1457 TimeAxisView::Children kids = (*t)->get_child_list();
1458 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1460 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1461 if ((*ci)->hidden()) {
1465 std::pair<TimeAxisView*,double> dev;
1466 dev = (*ci)->covers_y_position (top_of_trackviews);
1468 /* some automation lane is currently at the top */
1469 if (ci == kids.rbegin()) {
1470 /* first (bottom-most) autmation lane is at the top.
1471 * -> move to next track
1480 if (nkid != kids.rend()) {
1481 ensure_time_axis_view_is_visible (**nkid, true);
1489 /* move to the track below the first one that covers the */
1491 if (next != track_views.rend()) {
1492 ensure_time_axis_view_is_visible (**next, true);
1500 Editor::scroll_up_one_track (bool skip_child_views)
1502 TrackViewList::iterator prev = track_views.end();
1503 double top_of_trackviews = vertical_adjustment.get_value ();
1505 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1507 if ((*t)->hidden()) {
1511 /* find the trackview at the top of the trackview group
1513 * Note that covers_y_position() is recursive and includes child views
1515 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1518 if (skip_child_views) {
1521 /* automation lane (one level, non-recursive)
1523 * - if no automation lane exists -> move to prev tack
1524 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1525 * (actually last automation lane of previous track, see below)
1526 * - if first (top-most) lane is at the top -> move to this track
1527 * - else move up one lane
1529 TimeAxisView::Children kids = (*t)->get_child_list();
1530 TimeAxisView::Children::iterator pkid = kids.end();
1532 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1533 if ((*ci)->hidden()) {
1537 std::pair<TimeAxisView*,double> dev;
1538 dev = (*ci)->covers_y_position (top_of_trackviews);
1540 /* some automation lane is currently at the top */
1541 if (ci == kids.begin()) {
1542 /* first (top-most) autmation lane is at the top.
1543 * jump directly to this track's top
1545 ensure_time_axis_view_is_visible (**t, true);
1548 else if (pkid != kids.end()) {
1549 /* some other automation lane is at the top.
1550 * move up to prev automation lane.
1552 ensure_time_axis_view_is_visible (**pkid, true);
1555 assert(0); // not reached
1566 if (prev != track_views.end()) {
1567 // move to bottom-most automation-lane of the previous track
1568 TimeAxisView::Children kids = (*prev)->get_child_list();
1569 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1570 if (!skip_child_views) {
1571 // find the last visible lane
1572 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1573 if (!(*ci)->hidden()) {
1579 if (pkid != kids.rend()) {
1580 ensure_time_axis_view_is_visible (**pkid, true);
1582 ensure_time_axis_view_is_visible (**prev, true);
1593 Editor::tav_zoom_step (bool coarser)
1595 DisplaySuspender ds;
1599 if (selection->tracks.empty()) {
1602 ts = &selection->tracks;
1605 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1606 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1607 tv->step_height (coarser);
1612 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1614 DisplaySuspender ds;
1618 if (selection->tracks.empty() || force_all) {
1621 ts = &selection->tracks;
1624 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1625 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1626 uint32_t h = tv->current_height ();
1631 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1636 tv->set_height (h + 5);
1643 Editor::temporal_zoom_step (bool coarser)
1645 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1647 framecnt_t nspp = samples_per_pixel;
1655 temporal_zoom (nspp);
1659 Editor::temporal_zoom (framecnt_t fpp)
1665 framepos_t current_page = current_page_samples();
1666 framepos_t current_leftmost = leftmost_frame;
1667 framepos_t current_rightmost;
1668 framepos_t current_center;
1669 framepos_t new_page_size;
1670 framepos_t half_page_size;
1671 framepos_t leftmost_after_zoom = 0;
1673 bool in_track_canvas;
1677 if (fpp == samples_per_pixel) {
1681 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1682 // segfaults for lack of memory. If somebody decides this is not high enough I
1683 // believe it can be raisen to higher values but some limit must be in place.
1685 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1686 // all of which is used for the editor track displays. The whole day
1687 // would be 4147200000 samples, so 2592000 samples per pixel.
1689 nfpp = min (fpp, (framecnt_t) 2592000);
1690 nfpp = max ((framecnt_t) 1, nfpp);
1692 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1693 half_page_size = new_page_size / 2;
1695 switch (zoom_focus) {
1697 leftmost_after_zoom = current_leftmost;
1700 case ZoomFocusRight:
1701 current_rightmost = leftmost_frame + current_page;
1702 if (current_rightmost < new_page_size) {
1703 leftmost_after_zoom = 0;
1705 leftmost_after_zoom = current_rightmost - new_page_size;
1709 case ZoomFocusCenter:
1710 current_center = current_leftmost + (current_page/2);
1711 if (current_center < half_page_size) {
1712 leftmost_after_zoom = 0;
1714 leftmost_after_zoom = current_center - half_page_size;
1718 case ZoomFocusPlayhead:
1719 /* centre playhead */
1720 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1723 leftmost_after_zoom = 0;
1724 } else if (l > max_framepos) {
1725 leftmost_after_zoom = max_framepos - new_page_size;
1727 leftmost_after_zoom = (framepos_t) l;
1731 case ZoomFocusMouse:
1732 /* try to keep the mouse over the same point in the display */
1734 if (!mouse_frame (where, in_track_canvas)) {
1735 /* use playhead instead */
1736 where = playhead_cursor->current_frame ();
1738 if (where < half_page_size) {
1739 leftmost_after_zoom = 0;
1741 leftmost_after_zoom = where - half_page_size;
1746 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1749 leftmost_after_zoom = 0;
1750 } else if (l > max_framepos) {
1751 leftmost_after_zoom = max_framepos - new_page_size;
1753 leftmost_after_zoom = (framepos_t) l;
1760 /* try to keep the edit point in the same place */
1761 where = get_preferred_edit_position ();
1765 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1768 leftmost_after_zoom = 0;
1769 } else if (l > max_framepos) {
1770 leftmost_after_zoom = max_framepos - new_page_size;
1772 leftmost_after_zoom = (framepos_t) l;
1776 /* edit point not defined */
1783 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1785 reposition_and_zoom (leftmost_after_zoom, nfpp);
1789 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1791 /* this func helps make sure we leave a little space
1792 at each end of the editor so that the zoom doesn't fit the region
1793 precisely to the screen.
1796 GdkScreen* screen = gdk_screen_get_default ();
1797 const gint pixwidth = gdk_screen_get_width (screen);
1798 const gint mmwidth = gdk_screen_get_width_mm (screen);
1799 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1800 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1802 const framepos_t range = end - start;
1803 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1804 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1806 if (start > extra_samples) {
1807 start -= extra_samples;
1812 if (max_framepos - extra_samples > end) {
1813 end += extra_samples;
1820 Editor::temporal_zoom_region (bool both_axes)
1822 framepos_t start = max_framepos;
1824 set<TimeAxisView*> tracks;
1826 if ( !get_selection_extents(start, end) )
1829 calc_extra_zoom_edges (start, end);
1831 /* if we're zooming on both axes we need to save track heights etc.
1834 undo_visual_stack.push_back (current_visual_state (both_axes));
1836 PBD::Unwinder<bool> nsv (no_save_visual, true);
1838 temporal_zoom_by_frame (start, end);
1841 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1843 /* set visible track heights appropriately */
1845 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1846 (*t)->set_height (per_track_height);
1849 /* hide irrelevant tracks */
1851 DisplaySuspender ds;
1853 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1854 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1855 hide_track_in_display (*i);
1859 vertical_adjustment.set_value (0.0);
1862 redo_visual_stack.push_back (current_visual_state (both_axes));
1867 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1869 start = max_framepos;
1873 //ToDo: if notes are selected, set extents to that selection
1875 //ToDo: if control points are selected, set extents to that selection
1877 if ( !selection->regions.empty() ) {
1878 RegionSelection rs = get_regions_from_selection_and_entered ();
1880 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1882 if ((*i)->region()->position() < start) {
1883 start = (*i)->region()->position();
1886 if ((*i)->region()->last_frame() + 1 > end) {
1887 end = (*i)->region()->last_frame() + 1;
1891 } else if (!selection->time.empty()) {
1892 start = selection->time.start();
1893 end = selection->time.end_frame();
1895 ret = false; //no selection found
1898 if ((start == 0 && end == 0) || end < start) {
1907 Editor::temporal_zoom_selection (bool both_axes)
1909 if (!selection) return;
1911 //ToDo: if notes are selected, zoom to that
1913 //ToDo: if control points are selected, zoom to that
1915 //if region(s) are selected, zoom to that
1916 if ( !selection->regions.empty() )
1917 temporal_zoom_region (both_axes);
1919 //if a range is selected, zoom to that
1920 if (!selection->time.empty()) {
1922 framepos_t start, end;
1923 if (get_selection_extents (start, end)) {
1924 calc_extra_zoom_edges(start, end);
1925 temporal_zoom_by_frame (start, end);
1935 Editor::temporal_zoom_session ()
1937 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1940 framecnt_t start = _session->current_start_frame();
1941 framecnt_t end = _session->current_end_frame();
1943 if (_session->actively_recording () ) {
1944 framepos_t cur = playhead_cursor->current_frame ();
1946 /* recording beyond the end marker; zoom out
1947 * by 5 seconds more so that if 'follow
1948 * playhead' is active we don't immediately
1951 end = cur + _session->frame_rate() * 5;
1955 if ((start == 0 && end == 0) || end < start) {
1959 calc_extra_zoom_edges(start, end);
1961 temporal_zoom_by_frame (start, end);
1966 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1968 if (!_session) return;
1970 if ((start == 0 && end == 0) || end < start) {
1974 framepos_t range = end - start;
1976 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1978 framepos_t new_page = range;
1979 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1980 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1982 if (new_leftmost > middle) {
1986 if (new_leftmost < 0) {
1990 reposition_and_zoom (new_leftmost, new_fpp);
1994 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2000 framecnt_t range_before = frame - leftmost_frame;
2004 if (samples_per_pixel <= 1) {
2007 new_spp = samples_per_pixel + (samples_per_pixel/2);
2009 range_before += range_before/2;
2011 if (samples_per_pixel >= 1) {
2012 new_spp = samples_per_pixel - (samples_per_pixel/2);
2014 /* could bail out here since we cannot zoom any finer,
2015 but leave that to the equality test below
2017 new_spp = samples_per_pixel;
2020 range_before -= range_before/2;
2023 if (new_spp == samples_per_pixel) {
2027 /* zoom focus is automatically taken as @param frame when this
2031 framepos_t new_leftmost = frame - (framepos_t)range_before;
2033 if (new_leftmost > frame) {
2037 if (new_leftmost < 0) {
2041 reposition_and_zoom (new_leftmost, new_spp);
2046 Editor::choose_new_marker_name(string &name) {
2048 if (!UIConfiguration::instance().get_name_new_markers()) {
2049 /* don't prompt user for a new name */
2053 ArdourPrompter dialog (true);
2055 dialog.set_prompt (_("New Name:"));
2057 dialog.set_title (_("New Location Marker"));
2059 dialog.set_name ("MarkNameWindow");
2060 dialog.set_size_request (250, -1);
2061 dialog.set_position (Gtk::WIN_POS_MOUSE);
2063 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2064 dialog.set_initial_text (name);
2068 switch (dialog.run ()) {
2069 case RESPONSE_ACCEPT:
2075 dialog.get_result(name);
2082 Editor::add_location_from_selection ()
2086 if (selection->time.empty()) {
2090 if (_session == 0 || clicked_axisview == 0) {
2094 framepos_t start = selection->time[clicked_selection].start;
2095 framepos_t end = selection->time[clicked_selection].end;
2097 _session->locations()->next_available_name(rangename,"selection");
2098 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2100 begin_reversible_command (_("add marker"));
2102 XMLNode &before = _session->locations()->get_state();
2103 _session->locations()->add (location, true);
2104 XMLNode &after = _session->locations()->get_state();
2105 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2107 commit_reversible_command ();
2111 Editor::add_location_mark (framepos_t where)
2115 select_new_marker = true;
2117 _session->locations()->next_available_name(markername,"mark");
2118 if (!choose_new_marker_name(markername)) {
2121 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2122 begin_reversible_command (_("add marker"));
2124 XMLNode &before = _session->locations()->get_state();
2125 _session->locations()->add (location, true);
2126 XMLNode &after = _session->locations()->get_state();
2127 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2129 commit_reversible_command ();
2133 Editor::set_session_start_from_playhead ()
2139 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2140 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2142 XMLNode &before = loc->get_state();
2144 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2146 XMLNode &after = loc->get_state();
2148 begin_reversible_command (_("Set session start"));
2150 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2152 commit_reversible_command ();
2157 Editor::set_session_end_from_playhead ()
2163 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2164 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2166 XMLNode &before = loc->get_state();
2168 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2170 XMLNode &after = loc->get_state();
2172 begin_reversible_command (_("Set session start"));
2174 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2176 commit_reversible_command ();
2181 Editor::add_location_from_playhead_cursor ()
2183 add_location_mark (_session->audible_frame());
2187 Editor::remove_location_at_playhead_cursor ()
2191 XMLNode &before = _session->locations()->get_state();
2192 bool removed = false;
2194 //find location(s) at this time
2195 Locations::LocationList locs;
2196 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2197 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2198 if ((*i)->is_mark()) {
2199 _session->locations()->remove (*i);
2206 begin_reversible_command (_("remove marker"));
2207 XMLNode &after = _session->locations()->get_state();
2208 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2209 commit_reversible_command ();
2214 /** Add a range marker around each selected region */
2216 Editor::add_locations_from_region ()
2218 RegionSelection rs = get_regions_from_selection_and_entered ();
2223 bool commit = false;
2225 XMLNode &before = _session->locations()->get_state();
2227 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2229 boost::shared_ptr<Region> region = (*i)->region ();
2231 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2233 _session->locations()->add (location, true);
2238 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2239 XMLNode &after = _session->locations()->get_state();
2240 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2241 commit_reversible_command ();
2245 /** Add a single range marker around all selected regions */
2247 Editor::add_location_from_region ()
2249 RegionSelection rs = get_regions_from_selection_and_entered ();
2255 XMLNode &before = _session->locations()->get_state();
2259 if (rs.size() > 1) {
2260 _session->locations()->next_available_name(markername, "regions");
2262 RegionView* rv = *(rs.begin());
2263 boost::shared_ptr<Region> region = rv->region();
2264 markername = region->name();
2267 if (!choose_new_marker_name(markername)) {
2271 // single range spanning all selected
2272 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2273 _session->locations()->add (location, true);
2275 begin_reversible_command (_("add marker"));
2276 XMLNode &after = _session->locations()->get_state();
2277 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2278 commit_reversible_command ();
2284 Editor::jump_forward_to_mark ()
2290 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2296 _session->request_locate (pos, _session->transport_rolling());
2300 Editor::jump_backward_to_mark ()
2306 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2312 _session->request_locate (pos, _session->transport_rolling());
2318 framepos_t const pos = _session->audible_frame ();
2321 _session->locations()->next_available_name (markername, "mark");
2323 if (!choose_new_marker_name (markername)) {
2327 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2331 Editor::clear_markers ()
2334 begin_reversible_command (_("clear markers"));
2336 XMLNode &before = _session->locations()->get_state();
2337 _session->locations()->clear_markers ();
2338 XMLNode &after = _session->locations()->get_state();
2339 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2341 commit_reversible_command ();
2346 Editor::clear_ranges ()
2349 begin_reversible_command (_("clear ranges"));
2351 XMLNode &before = _session->locations()->get_state();
2353 _session->locations()->clear_ranges ();
2355 XMLNode &after = _session->locations()->get_state();
2356 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2358 commit_reversible_command ();
2363 Editor::clear_locations ()
2365 begin_reversible_command (_("clear locations"));
2367 XMLNode &before = _session->locations()->get_state();
2368 _session->locations()->clear ();
2369 XMLNode &after = _session->locations()->get_state();
2370 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2372 commit_reversible_command ();
2376 Editor::unhide_markers ()
2378 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2379 Location *l = (*i).first;
2380 if (l->is_hidden() && l->is_mark()) {
2381 l->set_hidden(false, this);
2387 Editor::unhide_ranges ()
2389 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2390 Location *l = (*i).first;
2391 if (l->is_hidden() && l->is_range_marker()) {
2392 l->set_hidden(false, this);
2397 /* INSERT/REPLACE */
2400 Editor::insert_region_list_selection (float times)
2402 RouteTimeAxisView *tv = 0;
2403 boost::shared_ptr<Playlist> playlist;
2405 if (clicked_routeview != 0) {
2406 tv = clicked_routeview;
2407 } else if (!selection->tracks.empty()) {
2408 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2411 } else if (entered_track != 0) {
2412 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2419 if ((playlist = tv->playlist()) == 0) {
2423 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2428 begin_reversible_command (_("insert region"));
2429 playlist->clear_changes ();
2430 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2431 if (Config->get_edit_mode() == Ripple)
2432 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2434 _session->add_command(new StatefulDiffCommand (playlist));
2435 commit_reversible_command ();
2438 /* BUILT-IN EFFECTS */
2441 Editor::reverse_selection ()
2446 /* GAIN ENVELOPE EDITING */
2449 Editor::edit_envelope ()
2456 Editor::transition_to_rolling (bool fwd)
2462 if (_session->config.get_external_sync()) {
2463 switch (Config->get_sync_source()) {
2467 /* transport controlled by the master */
2472 if (_session->is_auditioning()) {
2473 _session->cancel_audition ();
2477 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2481 Editor::play_from_start ()
2483 _session->request_locate (_session->current_start_frame(), true);
2487 Editor::play_from_edit_point ()
2489 _session->request_locate (get_preferred_edit_position(), true);
2493 Editor::play_from_edit_point_and_return ()
2495 framepos_t start_frame;
2496 framepos_t return_frame;
2498 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2500 if (_session->transport_rolling()) {
2501 _session->request_locate (start_frame, false);
2505 /* don't reset the return frame if its already set */
2507 if ((return_frame = _session->requested_return_frame()) < 0) {
2508 return_frame = _session->audible_frame();
2511 if (start_frame >= 0) {
2512 _session->request_roll_at_and_return (start_frame, return_frame);
2517 Editor::play_selection ()
2519 framepos_t start, end;
2520 if (!get_selection_extents ( start, end))
2523 AudioRange ar (start, end, 0);
2524 list<AudioRange> lar;
2527 _session->request_play_range (&lar, true);
2531 Editor::get_preroll ()
2533 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2538 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2540 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits )
2543 location -= get_preroll();
2545 //don't try to locate before the beginning of time
2549 //if follow_playhead is on, keep the playhead on the screen
2550 if ( _follow_playhead )
2551 if ( location < leftmost_frame )
2552 location = leftmost_frame;
2554 _session->request_locate( location );
2558 Editor::play_with_preroll ()
2561 framepos_t preroll = get_preroll();
2563 framepos_t start, end;
2564 if (!get_selection_extents ( start, end))
2567 if (start > preroll)
2568 start = start - preroll;
2570 end = end + preroll; //"post-roll"
2572 AudioRange ar (start, end, 0);
2573 list<AudioRange> lar;
2576 _session->request_play_range (&lar, true);
2581 Editor::play_location (Location& location)
2583 if (location.start() <= location.end()) {
2587 _session->request_bounded_roll (location.start(), location.end());
2591 Editor::loop_location (Location& location)
2593 if (location.start() <= location.end()) {
2599 if ((tll = transport_loop_location()) != 0) {
2600 tll->set (location.start(), location.end());
2602 // enable looping, reposition and start rolling
2603 _session->request_locate (tll->start(), true);
2604 _session->request_play_loop (true);
2609 Editor::do_layer_operation (LayerOperation op)
2611 if (selection->regions.empty ()) {
2615 bool const multiple = selection->regions.size() > 1;
2619 begin_reversible_command (_("raise regions"));
2621 begin_reversible_command (_("raise region"));
2627 begin_reversible_command (_("raise regions to top"));
2629 begin_reversible_command (_("raise region to top"));
2635 begin_reversible_command (_("lower regions"));
2637 begin_reversible_command (_("lower region"));
2643 begin_reversible_command (_("lower regions to bottom"));
2645 begin_reversible_command (_("lower region"));
2650 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2651 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2652 (*i)->clear_owned_changes ();
2655 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2656 boost::shared_ptr<Region> r = (*i)->region ();
2668 r->lower_to_bottom ();
2672 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2673 vector<Command*> cmds;
2675 _session->add_commands (cmds);
2678 commit_reversible_command ();
2682 Editor::raise_region ()
2684 do_layer_operation (Raise);
2688 Editor::raise_region_to_top ()
2690 do_layer_operation (RaiseToTop);
2694 Editor::lower_region ()
2696 do_layer_operation (Lower);
2700 Editor::lower_region_to_bottom ()
2702 do_layer_operation (LowerToBottom);
2705 /** Show the region editor for the selected regions */
2707 Editor::show_region_properties ()
2709 selection->foreach_regionview (&RegionView::show_region_editor);
2712 /** Show the midi list editor for the selected MIDI regions */
2714 Editor::show_midi_list_editor ()
2716 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2720 Editor::rename_region ()
2722 RegionSelection rs = get_regions_from_selection_and_entered ();
2728 ArdourDialog d (*this, _("Rename Region"), true, false);
2730 Label label (_("New name:"));
2733 hbox.set_spacing (6);
2734 hbox.pack_start (label, false, false);
2735 hbox.pack_start (entry, true, true);
2737 d.get_vbox()->set_border_width (12);
2738 d.get_vbox()->pack_start (hbox, false, false);
2740 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2741 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2743 d.set_size_request (300, -1);
2745 entry.set_text (rs.front()->region()->name());
2746 entry.select_region (0, -1);
2748 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2754 int const ret = d.run();
2758 if (ret != RESPONSE_OK) {
2762 std::string str = entry.get_text();
2763 strip_whitespace_edges (str);
2765 rs.front()->region()->set_name (str);
2766 _regions->redisplay ();
2771 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2773 if (_session->is_auditioning()) {
2774 _session->cancel_audition ();
2777 // note: some potential for creativity here, because region doesn't
2778 // have to belong to the playlist that Route is handling
2780 // bool was_soloed = route.soloed();
2782 route.set_solo (true, this);
2784 _session->request_bounded_roll (region->position(), region->position() + region->length());
2786 /* XXX how to unset the solo state ? */
2789 /** Start an audition of the first selected region */
2791 Editor::play_edit_range ()
2793 framepos_t start, end;
2795 if (get_edit_op_range (start, end)) {
2796 _session->request_bounded_roll (start, end);
2801 Editor::play_selected_region ()
2803 framepos_t start = max_framepos;
2806 RegionSelection rs = get_regions_from_selection_and_entered ();
2812 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2813 if ((*i)->region()->position() < start) {
2814 start = (*i)->region()->position();
2816 if ((*i)->region()->last_frame() + 1 > end) {
2817 end = (*i)->region()->last_frame() + 1;
2821 _session->request_bounded_roll (start, end);
2825 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2827 _session->audition_region (region);
2831 Editor::region_from_selection ()
2833 if (clicked_axisview == 0) {
2837 if (selection->time.empty()) {
2841 framepos_t start = selection->time[clicked_selection].start;
2842 framepos_t end = selection->time[clicked_selection].end;
2844 TrackViewList tracks = get_tracks_for_range_action ();
2846 framepos_t selection_cnt = end - start + 1;
2848 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2849 boost::shared_ptr<Region> current;
2850 boost::shared_ptr<Playlist> pl;
2851 framepos_t internal_start;
2854 if ((pl = (*i)->playlist()) == 0) {
2858 if ((current = pl->top_region_at (start)) == 0) {
2862 internal_start = start - current->position();
2863 RegionFactory::region_name (new_name, current->name(), true);
2867 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2868 plist.add (ARDOUR::Properties::length, selection_cnt);
2869 plist.add (ARDOUR::Properties::name, new_name);
2870 plist.add (ARDOUR::Properties::layer, 0);
2872 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2877 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2879 if (selection->time.empty() || selection->tracks.empty()) {
2883 framepos_t start, end;
2884 if (clicked_selection) {
2885 start = selection->time[clicked_selection].start;
2886 end = selection->time[clicked_selection].end;
2888 start = selection->time.start();
2889 end = selection->time.end_frame();
2892 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2893 sort_track_selection (ts);
2895 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2896 boost::shared_ptr<Region> current;
2897 boost::shared_ptr<Playlist> playlist;
2898 framepos_t internal_start;
2901 if ((playlist = (*i)->playlist()) == 0) {
2905 if ((current = playlist->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, end - start + 1);
2916 plist.add (ARDOUR::Properties::name, new_name);
2918 new_regions.push_back (RegionFactory::create (current, plist));
2923 Editor::split_multichannel_region ()
2925 RegionSelection rs = get_regions_from_selection_and_entered ();
2931 vector< boost::shared_ptr<Region> > v;
2933 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2934 (*x)->region()->separate_by_channel (*_session, v);
2939 Editor::new_region_from_selection ()
2941 region_from_selection ();
2942 cancel_selection ();
2946 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2948 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2949 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2950 case Evoral::OverlapNone:
2958 * - selected tracks, or if there are none...
2959 * - tracks containing selected regions, or if there are none...
2964 Editor::get_tracks_for_range_action () const
2968 if (selection->tracks.empty()) {
2970 /* use tracks with selected regions */
2972 RegionSelection rs = selection->regions;
2974 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2975 TimeAxisView* tv = &(*i)->get_time_axis_view();
2977 if (!t.contains (tv)) {
2983 /* no regions and no tracks: use all tracks */
2989 t = selection->tracks;
2992 return t.filter_to_unique_playlists();
2996 Editor::separate_regions_between (const TimeSelection& ts)
2998 bool in_command = false;
2999 boost::shared_ptr<Playlist> playlist;
3000 RegionSelection new_selection;
3002 TrackViewList tmptracks = get_tracks_for_range_action ();
3003 sort_track_selection (tmptracks);
3005 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3007 RouteTimeAxisView* rtv;
3009 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3011 if (rtv->is_track()) {
3013 /* no edits to destructive tracks */
3015 if (rtv->track()->destructive()) {
3019 if ((playlist = rtv->playlist()) != 0) {
3021 playlist->clear_changes ();
3023 /* XXX need to consider musical time selections here at some point */
3025 double speed = rtv->track()->speed();
3028 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3030 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3031 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3033 latest_regionviews.clear ();
3035 playlist->partition ((framepos_t)((*t).start * speed),
3036 (framepos_t)((*t).end * speed), false);
3040 if (!latest_regionviews.empty()) {
3042 rtv->view()->foreach_regionview (sigc::bind (
3043 sigc::ptr_fun (add_if_covered),
3044 &(*t), &new_selection));
3047 begin_reversible_command (_("separate"));
3051 /* pick up changes to existing regions */
3053 vector<Command*> cmds;
3054 playlist->rdiff (cmds);
3055 _session->add_commands (cmds);
3057 /* pick up changes to the playlist itself (adds/removes)
3060 _session->add_command(new StatefulDiffCommand (playlist));
3069 // selection->set (new_selection);
3071 commit_reversible_command ();
3075 struct PlaylistState {
3076 boost::shared_ptr<Playlist> playlist;
3080 /** Take tracks from get_tracks_for_range_action and cut any regions
3081 * on those tracks so that the tracks are empty over the time
3085 Editor::separate_region_from_selection ()
3087 /* preferentially use *all* ranges in the time selection if we're in range mode
3088 to allow discontiguous operation, since get_edit_op_range() currently
3089 returns a single range.
3092 if (!selection->time.empty()) {
3094 separate_regions_between (selection->time);
3101 if (get_edit_op_range (start, end)) {
3103 AudioRange ar (start, end, 1);
3107 separate_regions_between (ts);
3113 Editor::separate_region_from_punch ()
3115 Location* loc = _session->locations()->auto_punch_location();
3117 separate_regions_using_location (*loc);
3122 Editor::separate_region_from_loop ()
3124 Location* loc = _session->locations()->auto_loop_location();
3126 separate_regions_using_location (*loc);
3131 Editor::separate_regions_using_location (Location& loc)
3133 if (loc.is_mark()) {
3137 AudioRange ar (loc.start(), loc.end(), 1);
3142 separate_regions_between (ts);
3145 /** Separate regions under the selected region */
3147 Editor::separate_under_selected_regions ()
3149 vector<PlaylistState> playlists;
3153 rs = get_regions_from_selection_and_entered();
3155 if (!_session || rs.empty()) {
3159 begin_reversible_command (_("separate region under"));
3161 list<boost::shared_ptr<Region> > regions_to_remove;
3163 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3164 // we can't just remove the region(s) in this loop because
3165 // this removes them from the RegionSelection, and they thus
3166 // disappear from underneath the iterator, and the ++i above
3167 // SEGVs in a puzzling fashion.
3169 // so, first iterate over the regions to be removed from rs and
3170 // add them to the regions_to_remove list, and then
3171 // iterate over the list to actually remove them.
3173 regions_to_remove.push_back ((*i)->region());
3176 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3178 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3181 // is this check necessary?
3185 vector<PlaylistState>::iterator i;
3187 //only take state if this is a new playlist.
3188 for (i = playlists.begin(); i != playlists.end(); ++i) {
3189 if ((*i).playlist == playlist) {
3194 if (i == playlists.end()) {
3196 PlaylistState before;
3197 before.playlist = playlist;
3198 before.before = &playlist->get_state();
3200 playlist->freeze ();
3201 playlists.push_back(before);
3204 //Partition on the region bounds
3205 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3207 //Re-add region that was just removed due to the partition operation
3208 playlist->add_region( (*rl), (*rl)->first_frame() );
3211 vector<PlaylistState>::iterator pl;
3213 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3214 (*pl).playlist->thaw ();
3215 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3218 commit_reversible_command ();
3222 Editor::crop_region_to_selection ()
3224 if (!selection->time.empty()) {
3226 crop_region_to (selection->time.start(), selection->time.end_frame());
3233 if (get_edit_op_range (start, end)) {
3234 crop_region_to (start, end);
3241 Editor::crop_region_to (framepos_t start, framepos_t end)
3243 vector<boost::shared_ptr<Playlist> > playlists;
3244 boost::shared_ptr<Playlist> playlist;
3247 if (selection->tracks.empty()) {
3248 ts = track_views.filter_to_unique_playlists();
3250 ts = selection->tracks.filter_to_unique_playlists ();
3253 sort_track_selection (ts);
3255 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3257 RouteTimeAxisView* rtv;
3259 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3261 boost::shared_ptr<Track> t = rtv->track();
3263 if (t != 0 && ! t->destructive()) {
3265 if ((playlist = rtv->playlist()) != 0) {
3266 playlists.push_back (playlist);
3272 if (playlists.empty()) {
3276 framepos_t the_start;
3279 bool in_command = false;
3281 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3283 boost::shared_ptr<Region> region;
3287 if ((region = (*i)->top_region_at(the_start)) == 0) {
3291 /* now adjust lengths to that we do the right thing
3292 if the selection extends beyond the region
3295 the_start = max (the_start, (framepos_t) region->position());
3296 if (max_framepos - the_start < region->length()) {
3297 the_end = the_start + region->length() - 1;
3299 the_end = max_framepos;
3301 the_end = min (end, the_end);
3302 cnt = the_end - the_start + 1;
3305 begin_reversible_command (_("trim to selection"));
3308 region->clear_changes ();
3309 region->trim_to (the_start, cnt);
3310 _session->add_command (new StatefulDiffCommand (region));
3314 commit_reversible_command ();
3319 Editor::region_fill_track ()
3321 RegionSelection rs = get_regions_from_selection_and_entered ();
3323 if (!_session || rs.empty()) {
3327 framepos_t const end = _session->current_end_frame ();
3328 RegionSelection foo;
3329 bool in_command = false;
3331 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3333 boost::shared_ptr<Region> region ((*i)->region());
3335 boost::shared_ptr<Playlist> pl = region->playlist();
3337 if (end <= region->last_frame()) {
3341 double times = (double) (end - region->last_frame()) / (double) region->length();
3348 begin_reversible_command (Operations::region_fill);
3351 TimeAxisView& tv = (*i)->get_time_axis_view();
3352 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3353 latest_regionviews.clear ();
3354 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3356 pl->clear_changes ();
3357 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3358 _session->add_command (new StatefulDiffCommand (pl));
3362 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3367 selection->set (foo);
3369 commit_reversible_command ();
3374 Editor::region_fill_selection ()
3376 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3380 if (selection->time.empty()) {
3384 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3389 framepos_t start = selection->time[clicked_selection].start;
3390 framepos_t end = selection->time[clicked_selection].end;
3392 boost::shared_ptr<Playlist> playlist;
3394 if (selection->tracks.empty()) {
3398 framepos_t selection_length = end - start;
3399 float times = (float)selection_length / region->length();
3400 bool in_command = false;
3402 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3403 RegionSelection foo;
3405 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3407 if ((playlist = (*i)->playlist()) == 0) {
3412 begin_reversible_command (Operations::fill_selection);
3415 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3416 latest_regionviews.clear ();
3417 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3419 playlist->clear_changes ();
3420 playlist->add_region (RegionFactory::create (region, true), start, times);
3421 _session->add_command (new StatefulDiffCommand (playlist));
3423 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3428 selection->set (foo);
3430 commit_reversible_command ();
3435 Editor::set_region_sync_position ()
3437 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3441 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3443 bool in_command = false;
3445 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3447 if (!(*r)->region()->covers (where)) {
3451 boost::shared_ptr<Region> region ((*r)->region());
3454 begin_reversible_command (_("set sync point"));
3458 region->clear_changes ();
3459 region->set_sync_position (where);
3460 _session->add_command(new StatefulDiffCommand (region));
3464 commit_reversible_command ();
3468 /** Remove the sync positions of the selection */
3470 Editor::remove_region_sync ()
3472 RegionSelection rs = get_regions_from_selection_and_entered ();
3478 begin_reversible_command (_("remove region sync"));
3480 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3482 (*i)->region()->clear_changes ();
3483 (*i)->region()->clear_sync_position ();
3484 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3487 commit_reversible_command ();
3491 Editor::naturalize_region ()
3493 RegionSelection rs = get_regions_from_selection_and_entered ();
3499 if (rs.size() > 1) {
3500 begin_reversible_command (_("move regions to original position"));
3502 begin_reversible_command (_("move region to original position"));
3505 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3506 (*i)->region()->clear_changes ();
3507 (*i)->region()->move_to_natural_position ();
3508 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3511 commit_reversible_command ();
3515 Editor::align_regions (RegionPoint what)
3517 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3523 begin_reversible_command (_("align selection"));
3525 framepos_t const position = get_preferred_edit_position ();
3527 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3528 align_region_internal ((*i)->region(), what, position);
3531 commit_reversible_command ();
3534 struct RegionSortByTime {
3535 bool operator() (const RegionView* a, const RegionView* b) {
3536 return a->region()->position() < b->region()->position();
3541 Editor::align_regions_relative (RegionPoint point)
3543 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3549 framepos_t const position = get_preferred_edit_position ();
3551 framepos_t distance = 0;
3555 list<RegionView*> sorted;
3556 rs.by_position (sorted);
3558 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3563 if (position > r->position()) {
3564 distance = position - r->position();
3566 distance = r->position() - position;
3572 if (position > r->last_frame()) {
3573 distance = position - r->last_frame();
3574 pos = r->position() + distance;
3576 distance = r->last_frame() - position;
3577 pos = r->position() - distance;
3583 pos = r->adjust_to_sync (position);
3584 if (pos > r->position()) {
3585 distance = pos - r->position();
3587 distance = r->position() - pos;
3593 if (pos == r->position()) {
3597 begin_reversible_command (_("align selection (relative)"));
3599 /* move first one specially */
3601 r->clear_changes ();
3602 r->set_position (pos);
3603 _session->add_command(new StatefulDiffCommand (r));
3605 /* move rest by the same amount */
3609 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3611 boost::shared_ptr<Region> region ((*i)->region());
3613 region->clear_changes ();
3616 region->set_position (region->position() + distance);
3618 region->set_position (region->position() - distance);
3621 _session->add_command(new StatefulDiffCommand (region));
3625 commit_reversible_command ();
3629 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3631 begin_reversible_command (_("align region"));
3632 align_region_internal (region, point, position);
3633 commit_reversible_command ();
3637 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3639 region->clear_changes ();
3643 region->set_position (region->adjust_to_sync (position));
3647 if (position > region->length()) {
3648 region->set_position (position - region->length());
3653 region->set_position (position);
3657 _session->add_command(new StatefulDiffCommand (region));
3661 Editor::trim_region_front ()
3667 Editor::trim_region_back ()
3669 trim_region (false);
3673 Editor::trim_region (bool front)
3675 framepos_t where = get_preferred_edit_position();
3676 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3682 begin_reversible_command (front ? _("trim front") : _("trim back"));
3684 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3685 if (!(*i)->region()->locked()) {
3687 (*i)->region()->clear_changes ();
3690 (*i)->region()->trim_front (where);
3691 maybe_locate_with_edit_preroll ( where );
3693 (*i)->region()->trim_end (where);
3694 maybe_locate_with_edit_preroll ( where );
3697 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3701 commit_reversible_command ();
3704 /** Trim the end of the selected regions to the position of the edit cursor */
3706 Editor::trim_region_to_loop ()
3708 Location* loc = _session->locations()->auto_loop_location();
3712 trim_region_to_location (*loc, _("trim to loop"));
3716 Editor::trim_region_to_punch ()
3718 Location* loc = _session->locations()->auto_punch_location();
3722 trim_region_to_location (*loc, _("trim to punch"));
3726 Editor::trim_region_to_location (const Location& loc, const char* str)
3728 RegionSelection rs = get_regions_from_selection_and_entered ();
3729 bool in_command = false;
3731 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3732 RegionView* rv = (*x);
3734 /* require region to span proposed trim */
3735 switch (rv->region()->coverage (loc.start(), loc.end())) {
3736 case Evoral::OverlapInternal:
3742 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3751 if (tav->track() != 0) {
3752 speed = tav->track()->speed();
3755 start = session_frame_to_track_frame (loc.start(), speed);
3756 end = session_frame_to_track_frame (loc.end(), speed);
3758 rv->region()->clear_changes ();
3759 rv->region()->trim_to (start, (end - start));
3762 begin_reversible_command (str);
3765 _session->add_command(new StatefulDiffCommand (rv->region()));
3769 commit_reversible_command ();
3774 Editor::trim_region_to_previous_region_end ()
3776 return trim_to_region(false);
3780 Editor::trim_region_to_next_region_start ()
3782 return trim_to_region(true);
3786 Editor::trim_to_region(bool forward)
3788 RegionSelection rs = get_regions_from_selection_and_entered ();
3789 bool in_command = false;
3791 boost::shared_ptr<Region> next_region;
3793 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3795 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3801 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3809 if (atav->track() != 0) {
3810 speed = atav->track()->speed();
3814 boost::shared_ptr<Region> region = arv->region();
3815 boost::shared_ptr<Playlist> playlist (region->playlist());
3817 region->clear_changes ();
3821 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3827 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3828 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3832 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3838 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3840 arv->region_changed (ARDOUR::bounds_change);
3844 begin_reversible_command (_("trim to region"));
3847 _session->add_command(new StatefulDiffCommand (region));
3851 commit_reversible_command ();
3856 Editor::unfreeze_route ()
3858 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3862 clicked_routeview->track()->unfreeze ();
3866 Editor::_freeze_thread (void* arg)
3868 return static_cast<Editor*>(arg)->freeze_thread ();
3872 Editor::freeze_thread ()
3874 /* create event pool because we may need to talk to the session */
3875 SessionEvent::create_per_thread_pool ("freeze events", 64);
3876 /* create per-thread buffers for process() tree to use */
3877 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3878 current_interthread_info->done = true;
3883 Editor::freeze_route ()
3889 /* stop transport before we start. this is important */
3891 _session->request_transport_speed (0.0);
3893 /* wait for just a little while, because the above call is asynchronous */
3895 Glib::usleep (250000);
3897 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3901 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3903 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3904 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3906 d.set_title (_("Cannot freeze"));
3911 if (clicked_routeview->track()->has_external_redirects()) {
3912 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"
3913 "Freezing will only process the signal as far as the first send/insert/return."),
3914 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3916 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3917 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3918 d.set_title (_("Freeze Limits"));
3920 int response = d.run ();
3923 case Gtk::RESPONSE_CANCEL:
3930 InterThreadInfo itt;
3931 current_interthread_info = &itt;
3933 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3935 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3937 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3939 while (!itt.done && !itt.cancel) {
3940 gtk_main_iteration ();
3943 current_interthread_info = 0;
3947 Editor::bounce_range_selection (bool replace, bool enable_processing)
3949 if (selection->time.empty()) {
3953 TrackSelection views = selection->tracks;
3955 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3957 if (enable_processing) {
3959 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3961 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3963 _("You can't perform this operation because the processing of the signal "
3964 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3965 "You can do this without processing, which is a different operation.")
3967 d.set_title (_("Cannot bounce"));
3974 framepos_t start = selection->time[clicked_selection].start;
3975 framepos_t end = selection->time[clicked_selection].end;
3976 framepos_t cnt = end - start + 1;
3977 bool in_command = false;
3979 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3981 RouteTimeAxisView* rtv;
3983 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3987 boost::shared_ptr<Playlist> playlist;
3989 if ((playlist = rtv->playlist()) == 0) {
3993 InterThreadInfo itt;
3995 playlist->clear_changes ();
3996 playlist->clear_owned_changes ();
3998 boost::shared_ptr<Region> r;
4000 if (enable_processing) {
4001 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4003 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4011 list<AudioRange> ranges;
4012 ranges.push_back (AudioRange (start, start+cnt, 0));
4013 playlist->cut (ranges); // discard result
4014 playlist->add_region (r, start);
4018 begin_reversible_command (_("bounce range"));
4021 vector<Command*> cmds;
4022 playlist->rdiff (cmds);
4023 _session->add_commands (cmds);
4025 _session->add_command (new StatefulDiffCommand (playlist));
4029 commit_reversible_command ();
4033 /** Delete selected regions, automation points or a time range */
4037 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4038 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4039 bool deleted = false;
4040 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4041 deleted = current_mixer_strip->delete_processors ();
4047 /** Cut selected regions, automation points or a time range */
4054 /** Copy selected regions, automation points or a time range */
4062 /** @return true if a Cut, Copy or Clear is possible */
4064 Editor::can_cut_copy () const
4066 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4073 /** Cut, copy or clear selected regions, automation points or a time range.
4074 * @param op Operation (Delete, Cut, Copy or Clear)
4077 Editor::cut_copy (CutCopyOp op)
4079 /* only cancel selection if cut/copy is successful.*/
4085 opname = _("delete");
4094 opname = _("clear");
4098 /* if we're deleting something, and the mouse is still pressed,
4099 the thing we started a drag for will be gone when we release
4100 the mouse button(s). avoid this. see part 2 at the end of
4104 if (op == Delete || op == Cut || op == Clear) {
4105 if (_drags->active ()) {
4110 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4111 cut_buffer->clear ();
4113 if (entered_marker) {
4115 /* cut/delete op while pointing at a marker */
4118 Location* loc = find_location_from_marker (entered_marker, ignored);
4120 if (_session && loc) {
4121 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4128 switch (mouse_mode) {
4131 begin_reversible_command (opname + ' ' + X_("MIDI"));
4133 commit_reversible_command ();
4139 bool did_edit = false;
4141 if (!selection->regions.empty() || !selection->points.empty()) {
4142 begin_reversible_command (opname + ' ' + _("objects"));
4145 if (!selection->regions.empty()) {
4146 cut_copy_regions (op, selection->regions);
4148 if (op == Cut || op == Delete) {
4149 selection->clear_regions ();
4153 if (!selection->points.empty()) {
4154 cut_copy_points (op);
4156 if (op == Cut || op == Delete) {
4157 selection->clear_points ();
4160 } else if (selection->time.empty()) {
4161 framepos_t start, end;
4162 /* no time selection, see if we can get an edit range
4165 if (get_edit_op_range (start, end)) {
4166 selection->set (start, end);
4168 } else if (!selection->time.empty()) {
4169 begin_reversible_command (opname + ' ' + _("range"));
4172 cut_copy_ranges (op);
4174 if (op == Cut || op == Delete) {
4175 selection->clear_time ();
4180 /* reset repeated paste state */
4183 commit_reversible_command ();
4186 if (op == Delete || op == Cut || op == Clear) {
4191 struct AutomationRecord {
4192 AutomationRecord () : state (0) , line(NULL) {}
4193 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4195 XMLNode* state; ///< state before any operation
4196 const AutomationLine* line; ///< line this came from
4197 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4200 /** Cut, copy or clear selected automation points.
4201 * @param op Operation (Cut, Copy or Clear)
4204 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4206 if (selection->points.empty ()) {
4210 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4211 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4213 /* Keep a record of the AutomationLists that we end up using in this operation */
4214 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4217 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4218 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4219 const AutomationLine& line = (*i)->line();
4220 const boost::shared_ptr<AutomationList> al = line.the_list();
4221 if (lists.find (al) == lists.end ()) {
4222 /* We haven't seen this list yet, so make a record for it. This includes
4223 taking a copy of its current state, in case this is needed for undo later.
4225 lists[al] = AutomationRecord (&al->get_state (), &line);
4229 if (op == Cut || op == Copy) {
4230 /* This operation will involve putting things in the cut buffer, so create an empty
4231 ControlList for each of our source lists to put the cut buffer data in.
4233 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4234 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4237 /* Add all selected points to the relevant copy ControlLists */
4238 framepos_t start = std::numeric_limits<framepos_t>::max();
4239 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4240 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4241 AutomationList::const_iterator j = (*i)->model();
4243 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4245 /* Update earliest MIDI start time in beats */
4246 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4248 /* Update earliest session start time in frames */
4249 start = std::min(start, (*i)->line().session_position(j));
4253 /* Snap start time backwards, so copy/paste is snap aligned. */
4255 if (earliest == Evoral::Beats::max()) {
4256 earliest = Evoral::Beats(); // Weird... don't offset
4258 earliest.round_down_to_beat();
4260 if (start == std::numeric_limits<double>::max()) {
4261 start = 0; // Weird... don't offset
4263 snap_to(start, RoundDownMaybe);
4266 const double line_offset = midi ? earliest.to_double() : start;
4267 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4268 /* Correct this copy list so that it is relative to the earliest
4269 start time, so relative ordering between points is preserved
4270 when copying from several lists and the paste starts at the
4271 earliest copied piece of data. */
4272 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4273 (*j)->when -= line_offset;
4276 /* And add it to the cut buffer */
4277 cut_buffer->add (i->second.copy);
4281 if (op == Delete || op == Cut) {
4282 /* This operation needs to remove things from the main AutomationList, so do that now */
4284 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4285 i->first->freeze ();
4288 /* Remove each selected point from its AutomationList */
4289 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4290 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4291 al->erase ((*i)->model ());
4294 /* Thaw the lists and add undo records for them */
4295 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4296 boost::shared_ptr<AutomationList> al = i->first;
4298 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4303 /** Cut, copy or clear selected automation points.
4304 * @param op Operation (Cut, Copy or Clear)
4307 Editor::cut_copy_midi (CutCopyOp op)
4309 Evoral::Beats earliest = Evoral::Beats::max();
4310 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4311 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4313 if (!mrv->selection().empty()) {
4314 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4316 mrv->cut_copy_clear (op);
4318 /* XXX: not ideal, as there may be more than one track involved in the selection */
4319 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4323 if (!selection->points.empty()) {
4324 cut_copy_points (op, earliest, true);
4325 if (op == Cut || op == Delete) {
4326 selection->clear_points ();
4331 struct lt_playlist {
4332 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4333 return a.playlist < b.playlist;
4337 struct PlaylistMapping {
4339 boost::shared_ptr<Playlist> pl;
4341 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4344 /** Remove `clicked_regionview' */
4346 Editor::remove_clicked_region ()
4348 if (clicked_routeview == 0 || clicked_regionview == 0) {
4352 begin_reversible_command (_("remove region"));
4354 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4356 playlist->clear_changes ();
4357 playlist->clear_owned_changes ();
4358 playlist->remove_region (clicked_regionview->region());
4359 if (Config->get_edit_mode() == Ripple)
4360 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4362 /* We might have removed regions, which alters other regions' layering_index,
4363 so we need to do a recursive diff here.
4365 vector<Command*> cmds;
4366 playlist->rdiff (cmds);
4367 _session->add_commands (cmds);
4369 _session->add_command(new StatefulDiffCommand (playlist));
4370 commit_reversible_command ();
4374 /** Remove the selected regions */
4376 Editor::remove_selected_regions ()
4378 RegionSelection rs = get_regions_from_selection_and_entered ();
4380 if (!_session || rs.empty()) {
4384 list<boost::shared_ptr<Region> > regions_to_remove;
4386 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4387 // we can't just remove the region(s) in this loop because
4388 // this removes them from the RegionSelection, and they thus
4389 // disappear from underneath the iterator, and the ++i above
4390 // SEGVs in a puzzling fashion.
4392 // so, first iterate over the regions to be removed from rs and
4393 // add them to the regions_to_remove list, and then
4394 // iterate over the list to actually remove them.
4396 regions_to_remove.push_back ((*i)->region());
4399 vector<boost::shared_ptr<Playlist> > playlists;
4401 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4403 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4406 // is this check necessary?
4410 /* get_regions_from_selection_and_entered() guarantees that
4411 the playlists involved are unique, so there is no need
4415 playlists.push_back (playlist);
4417 playlist->clear_changes ();
4418 playlist->clear_owned_changes ();
4419 playlist->freeze ();
4420 playlist->remove_region (*rl);
4421 if (Config->get_edit_mode() == Ripple)
4422 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4426 vector<boost::shared_ptr<Playlist> >::iterator pl;
4427 bool in_command = false;
4429 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4432 /* We might have removed regions, which alters other regions' layering_index,
4433 so we need to do a recursive diff here.
4437 begin_reversible_command (_("remove region"));
4440 vector<Command*> cmds;
4441 (*pl)->rdiff (cmds);
4442 _session->add_commands (cmds);
4444 _session->add_command(new StatefulDiffCommand (*pl));
4448 commit_reversible_command ();
4452 /** Cut, copy or clear selected regions.
4453 * @param op Operation (Cut, Copy or Clear)
4456 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4458 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4459 a map when we want ordered access to both elements. i think.
4462 vector<PlaylistMapping> pmap;
4464 framepos_t first_position = max_framepos;
4466 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4467 FreezeList freezelist;
4469 /* get ordering correct before we cut/copy */
4471 rs.sort_by_position_and_track ();
4473 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4475 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4477 if (op == Cut || op == Clear || op == Delete) {
4478 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4481 FreezeList::iterator fl;
4483 // only take state if this is a new playlist.
4484 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4490 if (fl == freezelist.end()) {
4491 pl->clear_changes();
4492 pl->clear_owned_changes ();
4494 freezelist.insert (pl);
4499 TimeAxisView* tv = &(*x)->get_time_axis_view();
4500 vector<PlaylistMapping>::iterator z;
4502 for (z = pmap.begin(); z != pmap.end(); ++z) {
4503 if ((*z).tv == tv) {
4508 if (z == pmap.end()) {
4509 pmap.push_back (PlaylistMapping (tv));
4513 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4515 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4518 /* region not yet associated with a playlist (e.g. unfinished
4525 TimeAxisView& tv = (*x)->get_time_axis_view();
4526 boost::shared_ptr<Playlist> npl;
4527 RegionSelection::iterator tmp;
4534 vector<PlaylistMapping>::iterator z;
4536 for (z = pmap.begin(); z != pmap.end(); ++z) {
4537 if ((*z).tv == &tv) {
4542 assert (z != pmap.end());
4545 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4553 boost::shared_ptr<Region> r = (*x)->region();
4554 boost::shared_ptr<Region> _xx;
4560 pl->remove_region (r);
4561 if (Config->get_edit_mode() == Ripple)
4562 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4566 _xx = RegionFactory::create (r);
4567 npl->add_region (_xx, r->position() - first_position);
4568 pl->remove_region (r);
4569 if (Config->get_edit_mode() == Ripple)
4570 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4574 /* copy region before adding, so we're not putting same object into two different playlists */
4575 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4579 pl->remove_region (r);
4580 if (Config->get_edit_mode() == Ripple)
4581 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4590 list<boost::shared_ptr<Playlist> > foo;
4592 /* the pmap is in the same order as the tracks in which selected regions occured */
4594 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4597 foo.push_back ((*i).pl);
4602 cut_buffer->set (foo);
4606 _last_cut_copy_source_track = 0;
4608 _last_cut_copy_source_track = pmap.front().tv;
4612 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4615 /* We might have removed regions, which alters other regions' layering_index,
4616 so we need to do a recursive diff here.
4618 vector<Command*> cmds;
4619 (*pl)->rdiff (cmds);
4620 _session->add_commands (cmds);
4622 _session->add_command (new StatefulDiffCommand (*pl));
4627 Editor::cut_copy_ranges (CutCopyOp op)
4629 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4631 /* Sort the track selection now, so that it if is used, the playlists
4632 selected by the calls below to cut_copy_clear are in the order that
4633 their tracks appear in the editor. This makes things like paste
4634 of ranges work properly.
4637 sort_track_selection (ts);
4640 if (!entered_track) {
4643 ts.push_back (entered_track);
4646 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4647 (*i)->cut_copy_clear (*selection, op);
4652 Editor::paste (float times, bool from_context)
4654 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4656 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4660 Editor::mouse_paste ()
4665 if (!mouse_frame (where, ignored)) {
4670 paste_internal (where, 1);
4674 Editor::paste_internal (framepos_t position, float times)
4676 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4678 if (cut_buffer->empty(internal_editing())) {
4682 if (position == max_framepos) {
4683 position = get_preferred_edit_position();
4684 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4687 if (position == last_paste_pos) {
4688 /* repeated paste in the same position */
4691 /* paste in new location, reset repeated paste state */
4693 last_paste_pos = position;
4696 /* get everything in the correct order */
4699 if (!selection->tracks.empty()) {
4700 /* If there is a track selection, paste into exactly those tracks and
4701 only those tracks. This allows the user to be explicit and override
4702 the below "do the reasonable thing" logic. */
4703 ts = selection->tracks.filter_to_unique_playlists ();
4704 sort_track_selection (ts);
4706 /* Figure out which track to base the paste at. */
4707 TimeAxisView* base_track = NULL;
4708 if (_edit_point == Editing::EditAtMouse && entered_track) {
4709 /* With the mouse edit point, paste onto the track under the mouse. */
4710 base_track = entered_track;
4711 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4712 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4713 base_track = &entered_regionview->get_time_axis_view();
4714 } else if (_last_cut_copy_source_track) {
4715 /* Paste to the track that the cut/copy came from (see mantis #333). */
4716 base_track = _last_cut_copy_source_track;
4718 /* This is "impossible" since we've copied... well, do nothing. */
4722 /* Walk up to parent if necessary, so base track is a route. */
4723 while (base_track->get_parent()) {
4724 base_track = base_track->get_parent();
4727 /* Add base track and all tracks below it. The paste logic will select
4728 the appropriate object types from the cut buffer in relative order. */
4729 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4730 if ((*i)->order() >= base_track->order()) {
4735 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4736 sort_track_selection (ts);
4738 /* Add automation children of each track in order, for pasting several lines. */
4739 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4740 /* Add any automation children for pasting several lines */
4741 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4746 typedef RouteTimeAxisView::AutomationTracks ATracks;
4747 const ATracks& atracks = rtv->automation_tracks();
4748 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4749 i = ts.insert(i, a->second.get());
4754 /* We now have a list of trackviews starting at base_track, including
4755 automation children, in the order shown in the editor, e.g. R1,
4756 R1.A1, R1.A2, R2, R2.A1, ... */
4759 begin_reversible_command (Operations::paste);
4761 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4762 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4763 /* Only one line copied, and one automation track selected. Do a
4764 "greedy" paste from one automation type to another. */
4766 PasteContext ctx(paste_count, times, ItemCounts(), true);
4767 ts.front()->paste (position, *cut_buffer, ctx);
4771 /* Paste into tracks */
4773 PasteContext ctx(paste_count, times, ItemCounts(), false);
4774 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4775 (*i)->paste (position, *cut_buffer, ctx);
4779 commit_reversible_command ();
4783 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4785 if (regions.empty ()) {
4789 boost::shared_ptr<Playlist> playlist;
4790 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4791 RegionSelection foo;
4793 framepos_t const start_frame = regions.start ();
4794 framepos_t const end_frame = regions.end_frame ();
4795 framecnt_t const gap = end_frame - start_frame;
4797 begin_reversible_command (Operations::duplicate_region);
4799 selection->clear_regions ();
4801 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4803 boost::shared_ptr<Region> r ((*i)->region());
4805 TimeAxisView& tv = (*i)->get_time_axis_view();
4806 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4807 latest_regionviews.clear ();
4808 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4810 framepos_t const position = end_frame + (r->first_frame() - start_frame);
4811 playlist = (*i)->region()->playlist();
4812 playlist->clear_changes ();
4813 playlist->duplicate (r, position, gap, times);
4814 _session->add_command(new StatefulDiffCommand (playlist));
4818 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4822 selection->set (foo);
4825 commit_reversible_command ();
4829 Editor::duplicate_selection (float times)
4831 if (selection->time.empty() || selection->tracks.empty()) {
4835 boost::shared_ptr<Playlist> playlist;
4836 vector<boost::shared_ptr<Region> > new_regions;
4837 vector<boost::shared_ptr<Region> >::iterator ri;
4839 create_region_from_selection (new_regions);
4841 if (new_regions.empty()) {
4845 ri = new_regions.begin();
4847 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4848 bool in_command = false;
4850 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4851 if ((playlist = (*i)->playlist()) == 0) {
4854 playlist->clear_changes ();
4856 if (clicked_selection) {
4857 end = selection->time[clicked_selection].end;
4859 end = selection->time.end_frame();
4861 playlist->duplicate (*ri, end, times);
4864 begin_reversible_command (_("duplicate selection"));
4867 _session->add_command (new StatefulDiffCommand (playlist));
4870 if (ri == new_regions.end()) {
4876 commit_reversible_command ();
4880 /** Reset all selected points to the relevant default value */
4882 Editor::reset_point_selection ()
4884 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4885 ARDOUR::AutomationList::iterator j = (*i)->model ();
4886 (*j)->value = (*i)->line().the_list()->default_value ();
4891 Editor::center_playhead ()
4893 float const page = _visible_canvas_width * samples_per_pixel;
4894 center_screen_internal (playhead_cursor->current_frame (), page);
4898 Editor::center_edit_point ()
4900 float const page = _visible_canvas_width * samples_per_pixel;
4901 center_screen_internal (get_preferred_edit_position(), page);
4904 /** Caller must begin and commit a reversible command */
4906 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4908 playlist->clear_changes ();
4910 _session->add_command (new StatefulDiffCommand (playlist));
4914 Editor::nudge_track (bool use_edit, bool forwards)
4916 boost::shared_ptr<Playlist> playlist;
4917 framepos_t distance;
4918 framepos_t next_distance;
4922 start = get_preferred_edit_position();
4927 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4931 if (selection->tracks.empty()) {
4935 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4936 bool in_command = false;
4938 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4940 if ((playlist = (*i)->playlist()) == 0) {
4944 playlist->clear_changes ();
4945 playlist->clear_owned_changes ();
4947 playlist->nudge_after (start, distance, forwards);
4950 begin_reversible_command (_("nudge track"));
4953 vector<Command*> cmds;
4955 playlist->rdiff (cmds);
4956 _session->add_commands (cmds);
4958 _session->add_command (new StatefulDiffCommand (playlist));
4962 commit_reversible_command ();
4967 Editor::remove_last_capture ()
4969 vector<string> choices;
4976 if (Config->get_verify_remove_last_capture()) {
4977 prompt = _("Do you really want to destroy the last capture?"
4978 "\n(This is destructive and cannot be undone)");
4980 choices.push_back (_("No, do nothing."));
4981 choices.push_back (_("Yes, destroy it."));
4983 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4985 if (prompter.run () == 1) {
4986 _session->remove_last_capture ();
4987 _regions->redisplay ();
4991 _session->remove_last_capture();
4992 _regions->redisplay ();
4997 Editor::normalize_region ()
5003 RegionSelection rs = get_regions_from_selection_and_entered ();
5009 NormalizeDialog dialog (rs.size() > 1);
5011 if (dialog.run () == RESPONSE_CANCEL) {
5015 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5018 /* XXX: should really only count audio regions here */
5019 int const regions = rs.size ();
5021 /* Make a list of the selected audio regions' maximum amplitudes, and also
5022 obtain the maximum amplitude of them all.
5024 list<double> max_amps;
5026 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5027 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5029 dialog.descend (1.0 / regions);
5030 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5033 /* the user cancelled the operation */
5037 max_amps.push_back (a);
5038 max_amp = max (max_amp, a);
5043 list<double>::const_iterator a = max_amps.begin ();
5044 bool in_command = false;
5046 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5047 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5052 arv->region()->clear_changes ();
5054 double const amp = dialog.normalize_individually() ? *a : max_amp;
5056 arv->audio_region()->normalize (amp, dialog.target ());
5059 begin_reversible_command (_("normalize"));
5062 _session->add_command (new StatefulDiffCommand (arv->region()));
5068 commit_reversible_command ();
5074 Editor::reset_region_scale_amplitude ()
5080 RegionSelection rs = get_regions_from_selection_and_entered ();
5086 bool in_command = false;
5088 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5089 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5092 arv->region()->clear_changes ();
5093 arv->audio_region()->set_scale_amplitude (1.0f);
5096 begin_reversible_command ("reset gain");
5099 _session->add_command (new StatefulDiffCommand (arv->region()));
5103 commit_reversible_command ();
5108 Editor::adjust_region_gain (bool up)
5110 RegionSelection rs = get_regions_from_selection_and_entered ();
5112 if (!_session || rs.empty()) {
5116 bool in_command = false;
5118 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5119 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5124 arv->region()->clear_changes ();
5126 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5134 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5137 begin_reversible_command ("adjust region gain");
5140 _session->add_command (new StatefulDiffCommand (arv->region()));
5144 commit_reversible_command ();
5150 Editor::reverse_region ()
5156 Reverse rev (*_session);
5157 apply_filter (rev, _("reverse regions"));
5161 Editor::strip_region_silence ()
5167 RegionSelection rs = get_regions_from_selection_and_entered ();
5173 std::list<RegionView*> audio_only;
5175 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5176 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5178 audio_only.push_back (arv);
5182 assert (!audio_only.empty());
5184 StripSilenceDialog d (_session, audio_only);
5185 int const r = d.run ();
5189 if (r == Gtk::RESPONSE_OK) {
5190 ARDOUR::AudioIntervalMap silences;
5191 d.silences (silences);
5192 StripSilence s (*_session, silences, d.fade_length());
5193 apply_filter (s, _("strip silence"), &d);
5198 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5200 Evoral::Sequence<Evoral::Beats>::Notes selected;
5201 mrv.selection_as_notelist (selected, true);
5203 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5204 v.push_back (selected);
5206 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5207 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5209 return op (mrv.midi_region()->model(), pos_beats, v);
5213 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5219 bool in_command = false;
5221 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5222 RegionSelection::const_iterator tmp = r;
5225 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5228 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5231 begin_reversible_command (op.name ());
5235 _session->add_command (cmd);
5243 commit_reversible_command ();
5248 Editor::fork_region ()
5250 RegionSelection rs = get_regions_from_selection_and_entered ();
5256 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5257 bool in_command = false;
5261 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5262 RegionSelection::iterator tmp = r;
5265 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5269 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5270 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5271 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5274 begin_reversible_command (_("Fork Region(s)"));
5277 playlist->clear_changes ();
5278 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5279 _session->add_command(new StatefulDiffCommand (playlist));
5281 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5289 commit_reversible_command ();
5294 Editor::quantize_region ()
5297 quantize_regions(get_regions_from_selection_and_entered ());
5302 Editor::quantize_regions (const RegionSelection& rs)
5304 if (rs.n_midi_regions() == 0) {
5308 if (!quantize_dialog) {
5309 quantize_dialog = new QuantizeDialog (*this);
5312 quantize_dialog->present ();
5313 const int r = quantize_dialog->run ();
5314 quantize_dialog->hide ();
5316 if (r == Gtk::RESPONSE_OK) {
5317 Quantize quant (quantize_dialog->snap_start(),
5318 quantize_dialog->snap_end(),
5319 quantize_dialog->start_grid_size(),
5320 quantize_dialog->end_grid_size(),
5321 quantize_dialog->strength(),
5322 quantize_dialog->swing(),
5323 quantize_dialog->threshold());
5325 apply_midi_note_edit_op (quant, rs);
5330 Editor::legatize_region (bool shrink_only)
5333 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5338 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5340 if (rs.n_midi_regions() == 0) {
5344 Legatize legatize(shrink_only);
5345 apply_midi_note_edit_op (legatize, rs);
5349 Editor::transform_region ()
5352 transform_regions(get_regions_from_selection_and_entered ());
5357 Editor::transform_regions (const RegionSelection& rs)
5359 if (rs.n_midi_regions() == 0) {
5363 TransformDialog* td = new TransformDialog();
5366 const int r = td->run();
5369 if (r == Gtk::RESPONSE_OK) {
5370 Transform transform(td->get());
5371 apply_midi_note_edit_op(transform, rs);
5376 Editor::insert_patch_change (bool from_context)
5378 RegionSelection rs = get_regions_from_selection_and_entered ();
5384 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5386 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5387 there may be more than one, but the PatchChangeDialog can only offer
5388 one set of patch menus.
5390 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5392 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5393 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5395 if (d.run() == RESPONSE_CANCEL) {
5399 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5400 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5402 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5403 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5410 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5412 RegionSelection rs = get_regions_from_selection_and_entered ();
5418 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5419 bool in_command = false;
5424 int const N = rs.size ();
5426 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5427 RegionSelection::iterator tmp = r;
5430 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5432 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5435 progress->descend (1.0 / N);
5438 if (arv->audio_region()->apply (filter, progress) == 0) {
5440 playlist->clear_changes ();
5441 playlist->clear_owned_changes ();
5443 if (filter.results.empty ()) {
5445 /* no regions returned; remove the old one */
5446 playlist->remove_region (arv->region ());
5450 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5452 /* first region replaces the old one */
5453 playlist->replace_region (arv->region(), *res, (*res)->position());
5457 while (res != filter.results.end()) {
5458 playlist->add_region (*res, (*res)->position());
5463 /* We might have removed regions, which alters other regions' layering_index,
5464 so we need to do a recursive diff here.
5468 begin_reversible_command (command);
5471 vector<Command*> cmds;
5472 playlist->rdiff (cmds);
5473 _session->add_commands (cmds);
5475 _session->add_command(new StatefulDiffCommand (playlist));
5479 progress->ascend ();
5488 commit_reversible_command ();
5493 Editor::external_edit_region ()
5499 Editor::reset_region_gain_envelopes ()
5501 RegionSelection rs = get_regions_from_selection_and_entered ();
5503 if (!_session || rs.empty()) {
5507 bool in_command = false;
5509 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5510 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5512 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5513 XMLNode& before (alist->get_state());
5515 arv->audio_region()->set_default_envelope ();
5518 begin_reversible_command (_("reset region gain"));
5521 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5526 commit_reversible_command ();
5531 Editor::set_region_gain_visibility (RegionView* rv)
5533 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5535 arv->update_envelope_visibility();
5540 Editor::set_gain_envelope_visibility ()
5546 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5547 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5549 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5555 Editor::toggle_gain_envelope_active ()
5557 if (_ignore_region_action) {
5561 RegionSelection rs = get_regions_from_selection_and_entered ();
5563 if (!_session || rs.empty()) {
5567 bool in_command = false;
5569 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5570 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5572 arv->region()->clear_changes ();
5573 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5576 begin_reversible_command (_("region gain envelope active"));
5579 _session->add_command (new StatefulDiffCommand (arv->region()));
5584 commit_reversible_command ();
5589 Editor::toggle_region_lock ()
5591 if (_ignore_region_action) {
5595 RegionSelection rs = get_regions_from_selection_and_entered ();
5597 if (!_session || rs.empty()) {
5601 begin_reversible_command (_("toggle region lock"));
5603 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5604 (*i)->region()->clear_changes ();
5605 (*i)->region()->set_locked (!(*i)->region()->locked());
5606 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5609 commit_reversible_command ();
5613 Editor::toggle_region_video_lock ()
5615 if (_ignore_region_action) {
5619 RegionSelection rs = get_regions_from_selection_and_entered ();
5621 if (!_session || rs.empty()) {
5625 begin_reversible_command (_("Toggle Video Lock"));
5627 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5628 (*i)->region()->clear_changes ();
5629 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5630 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5633 commit_reversible_command ();
5637 Editor::toggle_region_lock_style ()
5639 if (_ignore_region_action) {
5643 RegionSelection rs = get_regions_from_selection_and_entered ();
5645 if (!_session || rs.empty()) {
5649 begin_reversible_command (_("region lock style"));
5651 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5652 (*i)->region()->clear_changes ();
5653 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5654 (*i)->region()->set_position_lock_style (ns);
5655 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5658 commit_reversible_command ();
5662 Editor::toggle_opaque_region ()
5664 if (_ignore_region_action) {
5668 RegionSelection rs = get_regions_from_selection_and_entered ();
5670 if (!_session || rs.empty()) {
5674 begin_reversible_command (_("change region opacity"));
5676 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5677 (*i)->region()->clear_changes ();
5678 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5679 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5682 commit_reversible_command ();
5686 Editor::toggle_record_enable ()
5688 bool new_state = false;
5690 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5691 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5694 if (!rtav->is_track())
5698 new_state = !rtav->track()->record_enabled();
5702 rtav->track()->set_record_enabled (new_state, this);
5707 Editor::toggle_solo ()
5709 bool new_state = false;
5711 boost::shared_ptr<RouteList> rl (new RouteList);
5713 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5714 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5721 new_state = !rtav->route()->soloed ();
5725 rl->push_back (rtav->route());
5728 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5732 Editor::toggle_mute ()
5734 bool new_state = false;
5736 boost::shared_ptr<RouteList> rl (new RouteList);
5738 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5739 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5746 new_state = !rtav->route()->muted();
5750 rl->push_back (rtav->route());
5753 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5757 Editor::toggle_solo_isolate ()
5763 Editor::fade_range ()
5765 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5767 begin_reversible_command (_("fade range"));
5769 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5770 (*i)->fade_range (selection->time);
5773 commit_reversible_command ();
5778 Editor::set_fade_length (bool in)
5780 RegionSelection rs = get_regions_from_selection_and_entered ();
5786 /* we need a region to measure the offset from the start */
5788 RegionView* rv = rs.front ();
5790 framepos_t pos = get_preferred_edit_position();
5794 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5795 /* edit point is outside the relevant region */
5800 if (pos <= rv->region()->position()) {
5804 len = pos - rv->region()->position();
5805 cmd = _("set fade in length");
5807 if (pos >= rv->region()->last_frame()) {
5811 len = rv->region()->last_frame() - pos;
5812 cmd = _("set fade out length");
5815 bool in_command = false;
5817 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5818 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5824 boost::shared_ptr<AutomationList> alist;
5826 alist = tmp->audio_region()->fade_in();
5828 alist = tmp->audio_region()->fade_out();
5831 XMLNode &before = alist->get_state();
5834 tmp->audio_region()->set_fade_in_length (len);
5835 tmp->audio_region()->set_fade_in_active (true);
5837 tmp->audio_region()->set_fade_out_length (len);
5838 tmp->audio_region()->set_fade_out_active (true);
5842 begin_reversible_command (cmd);
5845 XMLNode &after = alist->get_state();
5846 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5850 commit_reversible_command ();
5855 Editor::set_fade_in_shape (FadeShape shape)
5857 RegionSelection rs = get_regions_from_selection_and_entered ();
5862 bool in_command = false;
5864 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5865 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5871 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5872 XMLNode &before = alist->get_state();
5874 tmp->audio_region()->set_fade_in_shape (shape);
5877 begin_reversible_command (_("set fade in shape"));
5880 XMLNode &after = alist->get_state();
5881 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5885 commit_reversible_command ();
5890 Editor::set_fade_out_shape (FadeShape shape)
5892 RegionSelection rs = get_regions_from_selection_and_entered ();
5897 bool in_command = false;
5899 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5900 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5906 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5907 XMLNode &before = alist->get_state();
5909 tmp->audio_region()->set_fade_out_shape (shape);
5912 begin_reversible_command (_("set fade out shape"));
5915 XMLNode &after = alist->get_state();
5916 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5920 commit_reversible_command ();
5925 Editor::set_fade_in_active (bool yn)
5927 RegionSelection rs = get_regions_from_selection_and_entered ();
5932 bool in_command = false;
5934 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5935 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5942 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5944 ar->clear_changes ();
5945 ar->set_fade_in_active (yn);
5948 begin_reversible_command (_("set fade in active"));
5951 _session->add_command (new StatefulDiffCommand (ar));
5955 commit_reversible_command ();
5960 Editor::set_fade_out_active (bool yn)
5962 RegionSelection rs = get_regions_from_selection_and_entered ();
5967 bool in_command = false;
5969 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5970 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5976 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5978 ar->clear_changes ();
5979 ar->set_fade_out_active (yn);
5982 begin_reversible_command (_("set fade out active"));
5985 _session->add_command(new StatefulDiffCommand (ar));
5989 commit_reversible_command ();
5994 Editor::toggle_region_fades (int dir)
5996 if (_ignore_region_action) {
6000 boost::shared_ptr<AudioRegion> ar;
6003 RegionSelection rs = get_regions_from_selection_and_entered ();
6009 RegionSelection::iterator i;
6010 for (i = rs.begin(); i != rs.end(); ++i) {
6011 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6013 yn = ar->fade_out_active ();
6015 yn = ar->fade_in_active ();
6021 if (i == rs.end()) {
6025 /* XXX should this undo-able? */
6026 bool in_command = false;
6028 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6029 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6032 ar->clear_changes ();
6034 if (dir == 1 || dir == 0) {
6035 ar->set_fade_in_active (!yn);
6038 if (dir == -1 || dir == 0) {
6039 ar->set_fade_out_active (!yn);
6042 begin_reversible_command (_("toggle fade active"));
6045 _session->add_command(new StatefulDiffCommand (ar));
6049 commit_reversible_command ();
6054 /** Update region fade visibility after its configuration has been changed */
6056 Editor::update_region_fade_visibility ()
6058 bool _fade_visibility = _session->config.get_show_region_fades ();
6060 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6061 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6063 if (_fade_visibility) {
6064 v->audio_view()->show_all_fades ();
6066 v->audio_view()->hide_all_fades ();
6073 Editor::set_edit_point ()
6078 if (!mouse_frame (where, ignored)) {
6084 if (selection->markers.empty()) {
6086 mouse_add_new_marker (where);
6091 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6094 loc->move_to (where);
6100 Editor::set_playhead_cursor ()
6102 if (entered_marker) {
6103 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6108 if (!mouse_frame (where, ignored)) {
6115 _session->request_locate (where, _session->transport_rolling());
6119 if (UIConfiguration::instance().get_follow_edits()) {
6120 cancel_time_selection();
6125 Editor::split_region ()
6127 if (_drags->active ()) {
6131 //if a range is selected, separate it
6132 if ( !selection->time.empty()) {
6133 separate_regions_between (selection->time);
6137 //if no range was selected, try to find some regions to split
6138 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6140 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6142 framepos_t where = get_preferred_edit_position ();
6148 split_regions_at (where, rs);
6152 struct EditorOrderRouteSorter {
6153 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6154 return a->order_key () < b->order_key ();
6159 Editor::select_next_route()
6161 if (selection->tracks.empty()) {
6162 selection->set (track_views.front());
6166 TimeAxisView* current = selection->tracks.front();
6170 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6171 if (*i == current) {
6173 if (i != track_views.end()) {
6176 current = (*(track_views.begin()));
6177 //selection->set (*(track_views.begin()));
6182 rui = dynamic_cast<RouteUI *>(current);
6183 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6185 selection->set(current);
6187 ensure_time_axis_view_is_visible (*current, false);
6191 Editor::select_prev_route()
6193 if (selection->tracks.empty()) {
6194 selection->set (track_views.front());
6198 TimeAxisView* current = selection->tracks.front();
6202 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6203 if (*i == current) {
6205 if (i != track_views.rend()) {
6208 current = *(track_views.rbegin());
6213 rui = dynamic_cast<RouteUI *>(current);
6214 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6216 selection->set (current);
6218 ensure_time_axis_view_is_visible (*current, false);
6222 Editor::set_loop_from_selection (bool play)
6224 if (_session == 0) {
6228 framepos_t start, end;
6229 if (!get_selection_extents ( start, end))
6232 set_loop_range (start, end, _("set loop range from selection"));
6235 _session->request_play_loop (true, true);
6240 Editor::set_loop_from_region (bool play)
6242 framepos_t start, end;
6243 if (!get_selection_extents ( start, end))
6246 set_loop_range (start, end, _("set loop range from region"));
6249 _session->request_locate (start, true);
6250 _session->request_play_loop (true);
6255 Editor::set_punch_from_selection ()
6257 if (_session == 0) {
6261 framepos_t start, end;
6262 if (!get_selection_extents ( start, end))
6265 set_punch_range (start, end, _("set punch range from selection"));
6269 Editor::set_punch_from_loop ()
6271 if (_session == 0) {
6277 if ((tll = transport_loop_location()) == 0) {
6281 set_punch_range (tll->start(), tll->end(), _("set punch range from loop"));
6285 Editor::setup_loop_record ()
6287 if (_session == 0) {
6291 Location * looploc = _session->locations()->auto_loop_location();
6297 set_punch_range (looploc->start(), looploc->end(), _("setup loop recording"));
6299 Glib::RefPtr<Action> action = ActionManager::get_action ("Transport", "TogglePunch");
6303 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action);
6309 /* drive the other two actions from this one */
6311 Glib::RefPtr<Action> in_action = ActionManager::get_action ("Transport", "TogglePunchIn");
6312 Glib::RefPtr<Action> out_action = ActionManager::get_action ("Transport", "TogglePunchOut");
6314 if (in_action && out_action) {
6315 Glib::RefPtr<ToggleAction> tiact = Glib::RefPtr<ToggleAction>::cast_dynamic(in_action);
6316 Glib::RefPtr<ToggleAction> toact = Glib::RefPtr<ToggleAction>::cast_dynamic(out_action);
6317 tiact->set_active (true);
6318 toact->set_active (true);
6323 Editor::set_session_extents_from_selection ()
6325 if (_session == 0) {
6329 framepos_t start, end;
6330 if (!get_selection_extents ( start, end))
6334 if ((loc = _session->locations()->session_range_location()) == 0) {
6335 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6337 XMLNode &before = loc->get_state();
6339 _session->set_session_extents ( start, end );
6341 XMLNode &after = loc->get_state();
6343 begin_reversible_command (_("set session start/end from selection"));
6345 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6347 commit_reversible_command ();
6352 Editor::set_punch_start_from_edit_point ()
6356 framepos_t start = 0;
6357 framepos_t end = max_framepos;
6359 //use the existing punch end, if any
6360 Location* tpl = transport_punch_location();
6365 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6366 start = _session->audible_frame();
6368 start = get_preferred_edit_position();
6371 //snap the selection start/end
6374 //if there's not already a sensible selection endpoint, go "forever"
6375 if ( start > end ) {
6379 set_punch_range (start, end, _("set punch start from EP"));
6385 Editor::set_punch_end_from_edit_point ()
6389 framepos_t start = 0;
6390 framepos_t end = max_framepos;
6392 //use the existing punch start, if any
6393 Location* tpl = transport_punch_location();
6395 start = tpl->start();
6398 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6399 end = _session->audible_frame();
6401 end = get_preferred_edit_position();
6404 //snap the selection start/end
6407 set_punch_range (start, end, _("set punch end from EP"));
6413 Editor::set_loop_start_from_edit_point ()
6417 framepos_t start = 0;
6418 framepos_t end = max_framepos;
6420 //use the existing loop end, if any
6421 Location* tpl = transport_loop_location();
6426 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6427 start = _session->audible_frame();
6429 start = get_preferred_edit_position();
6432 //snap the selection start/end
6435 //if there's not already a sensible selection endpoint, go "forever"
6436 if ( start > end ) {
6440 set_loop_range (start, end, _("set loop start from EP"));
6446 Editor::set_loop_end_from_edit_point ()
6450 framepos_t start = 0;
6451 framepos_t end = max_framepos;
6453 //use the existing loop start, if any
6454 Location* tpl = transport_loop_location();
6456 start = tpl->start();
6459 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6460 end = _session->audible_frame();
6462 end = get_preferred_edit_position();
6465 //snap the selection start/end
6468 set_loop_range (start, end, _("set loop end from EP"));
6473 Editor::set_punch_from_region ()
6475 framepos_t start, end;
6476 if (!get_selection_extents ( start, end))
6479 set_punch_range (start, end, _("set punch range from region"));
6483 Editor::pitch_shift_region ()
6485 RegionSelection rs = get_regions_from_selection_and_entered ();
6487 RegionSelection audio_rs;
6488 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6489 if (dynamic_cast<AudioRegionView*> (*i)) {
6490 audio_rs.push_back (*i);
6494 if (audio_rs.empty()) {
6498 pitch_shift (audio_rs, 1.2);
6502 Editor::transpose_region ()
6504 RegionSelection rs = get_regions_from_selection_and_entered ();
6506 list<MidiRegionView*> midi_region_views;
6507 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6508 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6510 midi_region_views.push_back (mrv);
6515 int const r = d.run ();
6516 if (r != RESPONSE_ACCEPT) {
6520 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6521 (*i)->midi_region()->transpose (d.semitones ());
6526 Editor::set_tempo_from_region ()
6528 RegionSelection rs = get_regions_from_selection_and_entered ();
6530 if (!_session || rs.empty()) {
6534 RegionView* rv = rs.front();
6536 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6540 Editor::use_range_as_bar ()
6542 framepos_t start, end;
6543 if (get_edit_op_range (start, end)) {
6544 define_one_bar (start, end);
6549 Editor::define_one_bar (framepos_t start, framepos_t end)
6551 framepos_t length = end - start;
6553 const Meter& m (_session->tempo_map().meter_at (start));
6555 /* length = 1 bar */
6557 /* now we want frames per beat.
6558 we have frames per bar, and beats per bar, so ...
6561 /* XXXX METER MATH */
6563 double frames_per_beat = length / m.divisions_per_bar();
6565 /* beats per minute = */
6567 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6569 /* now decide whether to:
6571 (a) set global tempo
6572 (b) add a new tempo marker
6576 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6578 bool do_global = false;
6580 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6582 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6583 at the start, or create a new marker
6586 vector<string> options;
6587 options.push_back (_("Cancel"));
6588 options.push_back (_("Add new marker"));
6589 options.push_back (_("Set global tempo"));
6592 _("Define one bar"),
6593 _("Do you want to set the global tempo or add a new tempo marker?"),
6597 c.set_default_response (2);
6613 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6614 if the marker is at the region starter, change it, otherwise add
6619 begin_reversible_command (_("set tempo from region"));
6620 XMLNode& before (_session->tempo_map().get_state());
6623 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6624 } else if (t.frame() == start) {
6625 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6627 Timecode::BBT_Time bbt;
6628 _session->tempo_map().bbt_time (start, bbt);
6629 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6632 XMLNode& after (_session->tempo_map().get_state());
6634 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6635 commit_reversible_command ();
6639 Editor::split_region_at_transients ()
6641 AnalysisFeatureList positions;
6643 RegionSelection rs = get_regions_from_selection_and_entered ();
6645 if (!_session || rs.empty()) {
6649 begin_reversible_command (_("split regions"));
6651 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6653 RegionSelection::iterator tmp;
6658 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6660 if (ar && (ar->get_transients (positions) == 0)) {
6661 split_region_at_points ((*i)->region(), positions, true);
6668 commit_reversible_command ();
6673 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6675 bool use_rhythmic_rodent = false;
6677 boost::shared_ptr<Playlist> pl = r->playlist();
6679 list<boost::shared_ptr<Region> > new_regions;
6685 if (positions.empty()) {
6690 if (positions.size() > 20 && can_ferret) {
6691 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);
6692 MessageDialog msg (msgstr,
6695 Gtk::BUTTONS_OK_CANCEL);
6698 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6699 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6701 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6704 msg.set_title (_("Excessive split?"));
6707 int response = msg.run();
6713 case RESPONSE_APPLY:
6714 use_rhythmic_rodent = true;
6721 if (use_rhythmic_rodent) {
6722 show_rhythm_ferret ();
6726 AnalysisFeatureList::const_iterator x;
6728 pl->clear_changes ();
6729 pl->clear_owned_changes ();
6731 x = positions.begin();
6733 if (x == positions.end()) {
6738 pl->remove_region (r);
6742 while (x != positions.end()) {
6744 /* deal with positons that are out of scope of present region bounds */
6745 if (*x <= 0 || *x > r->length()) {
6750 /* file start = original start + how far we from the initial position ?
6753 framepos_t file_start = r->start() + pos;
6755 /* length = next position - current position
6758 framepos_t len = (*x) - pos;
6760 /* XXX we do we really want to allow even single-sample regions?
6761 shouldn't we have some kind of lower limit on region size?
6770 if (RegionFactory::region_name (new_name, r->name())) {
6774 /* do NOT announce new regions 1 by one, just wait till they are all done */
6778 plist.add (ARDOUR::Properties::start, file_start);
6779 plist.add (ARDOUR::Properties::length, len);
6780 plist.add (ARDOUR::Properties::name, new_name);
6781 plist.add (ARDOUR::Properties::layer, 0);
6783 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6784 /* because we set annouce to false, manually add the new region to the
6787 RegionFactory::map_add (nr);
6789 pl->add_region (nr, r->position() + pos);
6792 new_regions.push_front(nr);
6801 RegionFactory::region_name (new_name, r->name());
6803 /* Add the final region */
6806 plist.add (ARDOUR::Properties::start, r->start() + pos);
6807 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6808 plist.add (ARDOUR::Properties::name, new_name);
6809 plist.add (ARDOUR::Properties::layer, 0);
6811 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6812 /* because we set annouce to false, manually add the new region to the
6815 RegionFactory::map_add (nr);
6816 pl->add_region (nr, r->position() + pos);
6819 new_regions.push_front(nr);
6824 /* We might have removed regions, which alters other regions' layering_index,
6825 so we need to do a recursive diff here.
6827 vector<Command*> cmds;
6829 _session->add_commands (cmds);
6831 _session->add_command (new StatefulDiffCommand (pl));
6835 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6836 set_selected_regionview_from_region_list ((*i), Selection::Add);
6842 Editor::place_transient()
6848 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6854 framepos_t where = get_preferred_edit_position();
6856 begin_reversible_command (_("place transient"));
6858 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6859 framepos_t position = (*r)->region()->position();
6860 (*r)->region()->add_transient(where - position);
6863 commit_reversible_command ();
6867 Editor::remove_transient(ArdourCanvas::Item* item)
6873 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6876 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6877 _arv->remove_transient (*(float*) _line->get_data ("position"));
6881 Editor::snap_regions_to_grid ()
6883 list <boost::shared_ptr<Playlist > > used_playlists;
6885 RegionSelection rs = get_regions_from_selection_and_entered ();
6887 if (!_session || rs.empty()) {
6891 begin_reversible_command (_("snap regions to grid"));
6893 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6895 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6897 if (!pl->frozen()) {
6898 /* we haven't seen this playlist before */
6900 /* remember used playlists so we can thaw them later */
6901 used_playlists.push_back(pl);
6905 framepos_t start_frame = (*r)->region()->first_frame ();
6906 snap_to (start_frame);
6907 (*r)->region()->set_position (start_frame);
6910 while (used_playlists.size() > 0) {
6911 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6913 used_playlists.pop_front();
6916 commit_reversible_command ();
6920 Editor::close_region_gaps ()
6922 list <boost::shared_ptr<Playlist > > used_playlists;
6924 RegionSelection rs = get_regions_from_selection_and_entered ();
6926 if (!_session || rs.empty()) {
6930 Dialog dialog (_("Close Region Gaps"));
6933 table.set_spacings (12);
6934 table.set_border_width (12);
6935 Label* l = manage (left_aligned_label (_("Crossfade length")));
6936 table.attach (*l, 0, 1, 0, 1);
6938 SpinButton spin_crossfade (1, 0);
6939 spin_crossfade.set_range (0, 15);
6940 spin_crossfade.set_increments (1, 1);
6941 spin_crossfade.set_value (5);
6942 table.attach (spin_crossfade, 1, 2, 0, 1);
6944 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6946 l = manage (left_aligned_label (_("Pull-back length")));
6947 table.attach (*l, 0, 1, 1, 2);
6949 SpinButton spin_pullback (1, 0);
6950 spin_pullback.set_range (0, 100);
6951 spin_pullback.set_increments (1, 1);
6952 spin_pullback.set_value(30);
6953 table.attach (spin_pullback, 1, 2, 1, 2);
6955 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6957 dialog.get_vbox()->pack_start (table);
6958 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6959 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6962 if (dialog.run () == RESPONSE_CANCEL) {
6966 framepos_t crossfade_len = spin_crossfade.get_value();
6967 framepos_t pull_back_frames = spin_pullback.get_value();
6969 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6970 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6972 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6974 begin_reversible_command (_("close region gaps"));
6977 boost::shared_ptr<Region> last_region;
6979 rs.sort_by_position_and_track();
6981 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6983 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6985 if (!pl->frozen()) {
6986 /* we haven't seen this playlist before */
6988 /* remember used playlists so we can thaw them later */
6989 used_playlists.push_back(pl);
6993 framepos_t position = (*r)->region()->position();
6995 if (idx == 0 || position < last_region->position()){
6996 last_region = (*r)->region();
7001 (*r)->region()->trim_front( (position - pull_back_frames));
7002 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7004 last_region = (*r)->region();
7009 while (used_playlists.size() > 0) {
7010 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7012 used_playlists.pop_front();
7015 commit_reversible_command ();
7019 Editor::tab_to_transient (bool forward)
7021 AnalysisFeatureList positions;
7023 RegionSelection rs = get_regions_from_selection_and_entered ();
7029 framepos_t pos = _session->audible_frame ();
7031 if (!selection->tracks.empty()) {
7033 /* don't waste time searching for transients in duplicate playlists.
7036 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7038 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7040 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7043 boost::shared_ptr<Track> tr = rtv->track();
7045 boost::shared_ptr<Playlist> pl = tr->playlist ();
7047 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7050 positions.push_back (result);
7063 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7064 (*r)->region()->get_transients (positions);
7068 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7071 AnalysisFeatureList::iterator x;
7073 for (x = positions.begin(); x != positions.end(); ++x) {
7079 if (x != positions.end ()) {
7080 _session->request_locate (*x);
7084 AnalysisFeatureList::reverse_iterator x;
7086 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7092 if (x != positions.rend ()) {
7093 _session->request_locate (*x);
7099 Editor::playhead_forward_to_grid ()
7105 framepos_t pos = playhead_cursor->current_frame ();
7106 if (pos < max_framepos - 1) {
7108 snap_to_internal (pos, RoundUpAlways, false);
7109 _session->request_locate (pos);
7115 Editor::playhead_backward_to_grid ()
7121 framepos_t pos = playhead_cursor->current_frame ();
7124 snap_to_internal (pos, RoundDownAlways, false);
7125 _session->request_locate (pos);
7130 Editor::set_track_height (Height h)
7132 TrackSelection& ts (selection->tracks);
7134 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7135 (*x)->set_height_enum (h);
7140 Editor::toggle_tracks_active ()
7142 TrackSelection& ts (selection->tracks);
7144 bool target = false;
7150 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7151 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7155 target = !rtv->_route->active();
7158 rtv->_route->set_active (target, this);
7164 Editor::remove_tracks ()
7166 /* this will delete GUI objects that may be the subject of an event
7167 handler in which this method is called. Defer actual deletion to the
7168 next idle callback, when all event handling is finished.
7170 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7174 Editor::idle_remove_tracks ()
7177 return false; /* do not call again */
7181 Editor::_remove_tracks ()
7183 TrackSelection& ts (selection->tracks);
7189 vector<string> choices;
7193 const char* trackstr;
7195 vector<boost::shared_ptr<Route> > routes;
7196 bool special_bus = false;
7198 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7199 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7203 if (rtv->is_track()) {
7208 routes.push_back (rtv->_route);
7210 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7215 if (special_bus && !Config->get_allow_special_bus_removal()) {
7216 MessageDialog msg (_("That would be bad news ...."),
7220 msg.set_secondary_text (string_compose (_(
7221 "Removing the master or monitor bus is such a bad idea\n\
7222 that %1 is not going to allow it.\n\
7224 If you really want to do this sort of thing\n\
7225 edit your ardour.rc file to set the\n\
7226 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7233 if (ntracks + nbusses == 0) {
7237 trackstr = P_("track", "tracks", ntracks);
7238 busstr = P_("bus", "busses", nbusses);
7242 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7243 "(You may also lose the playlists associated with the %2)\n\n"
7244 "This action cannot be undone, and the session file will be overwritten!"),
7245 ntracks, trackstr, nbusses, busstr);
7247 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7248 "(You may also lose the playlists associated with the %2)\n\n"
7249 "This action cannot be undone, and the session file will be overwritten!"),
7252 } else if (nbusses) {
7253 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7254 "This action cannot be undone, and the session file will be overwritten"),
7258 choices.push_back (_("No, do nothing."));
7259 if (ntracks + nbusses > 1) {
7260 choices.push_back (_("Yes, remove them."));
7262 choices.push_back (_("Yes, remove it."));
7267 title = string_compose (_("Remove %1"), trackstr);
7269 title = string_compose (_("Remove %1"), busstr);
7272 Choice prompter (title, prompt, choices);
7274 if (prompter.run () != 1) {
7279 Session::StateProtector sp (_session);
7280 DisplaySuspender ds;
7281 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7282 _session->remove_route (*x);
7288 Editor::do_insert_time ()
7290 if (selection->tracks.empty()) {
7294 InsertRemoveTimeDialog d (*this);
7295 int response = d.run ();
7297 if (response != RESPONSE_OK) {
7301 if (d.distance() == 0) {
7305 InsertTimeOption opt = d.intersected_region_action ();
7308 get_preferred_edit_position(),
7314 d.move_glued_markers(),
7315 d.move_locked_markers(),
7321 Editor::insert_time (
7322 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7323 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7327 if (Config->get_edit_mode() == Lock) {
7330 bool in_command = false;
7332 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7334 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7338 /* don't operate on any playlist more than once, which could
7339 * happen if "all playlists" is enabled, but there is more
7340 * than 1 track using playlists "from" a given track.
7343 set<boost::shared_ptr<Playlist> > pl;
7345 if (all_playlists) {
7346 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7347 if (rtav && rtav->track ()) {
7348 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7349 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7354 if ((*x)->playlist ()) {
7355 pl.insert ((*x)->playlist ());
7359 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7361 (*i)->clear_changes ();
7362 (*i)->clear_owned_changes ();
7364 if (opt == SplitIntersected) {
7368 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7371 begin_reversible_command (_("insert time"));
7374 vector<Command*> cmds;
7376 _session->add_commands (cmds);
7378 _session->add_command (new StatefulDiffCommand (*i));
7382 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7385 begin_reversible_command (_("insert time"));
7388 rtav->route ()->shift (pos, frames);
7395 XMLNode& before (_session->locations()->get_state());
7396 Locations::LocationList copy (_session->locations()->list());
7398 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7400 Locations::LocationList::const_iterator tmp;
7402 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7403 bool const was_locked = (*i)->locked ();
7404 if (locked_markers_too) {
7408 if ((*i)->start() >= pos) {
7409 // move end first, in case we're moving by more than the length of the range
7410 if (!(*i)->is_mark()) {
7411 (*i)->set_end ((*i)->end() + frames);
7413 (*i)->set_start ((*i)->start() + frames);
7425 begin_reversible_command (_("insert time"));
7428 XMLNode& after (_session->locations()->get_state());
7429 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7435 begin_reversible_command (_("insert time"));
7438 XMLNode& before (_session->tempo_map().get_state());
7439 _session->tempo_map().insert_time (pos, frames);
7440 XMLNode& after (_session->tempo_map().get_state());
7441 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7445 commit_reversible_command ();
7450 Editor::do_remove_time ()
7452 if (selection->tracks.empty()) {
7456 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7457 InsertRemoveTimeDialog d (*this, true);
7459 int response = d.run ();
7461 if (response != RESPONSE_OK) {
7465 framecnt_t distance = d.distance();
7467 if (distance == 0) {
7477 d.move_glued_markers(),
7478 d.move_locked_markers(),
7484 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7485 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7487 if (Config->get_edit_mode() == Lock) {
7488 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7491 bool in_command = false;
7493 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7495 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7499 XMLNode &before = pl->get_state();
7501 std::list<AudioRange> rl;
7502 AudioRange ar(pos, pos+frames, 0);
7505 pl->shift (pos, -frames, true, ignore_music_glue);
7508 begin_reversible_command (_("cut time"));
7511 XMLNode &after = pl->get_state();
7513 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7517 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7520 begin_reversible_command (_("cut time"));
7523 rtav->route ()->shift (pos, -frames);
7527 std::list<Location*> loc_kill_list;
7532 XMLNode& before (_session->locations()->get_state());
7533 Locations::LocationList copy (_session->locations()->list());
7535 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7536 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7538 bool const was_locked = (*i)->locked ();
7539 if (locked_markers_too) {
7543 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7544 if ((*i)->end() >= pos
7545 && (*i)->end() < pos+frames
7546 && (*i)->start() >= pos
7547 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7549 loc_kill_list.push_back(*i);
7550 } else { // only start or end is included, try to do the right thing
7551 // move start before moving end, to avoid trying to move the end to before the start
7552 // if we're removing more time than the length of the range
7553 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7554 // start is within cut
7555 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7557 } else if ((*i)->start() >= pos+frames) {
7558 // start (and thus entire range) lies beyond end of cut
7559 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7562 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7563 // end is inside cut
7564 (*i)->set_end (pos); // bring the end to the cut
7566 } else if ((*i)->end() >= pos+frames) {
7567 // end is beyond end of cut
7568 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7573 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7574 loc_kill_list.push_back(*i);
7576 } else if ((*i)->start() >= pos) {
7577 (*i)->set_start ((*i)->start() -frames);
7587 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7588 _session->locations()->remove( *i );
7593 begin_reversible_command (_("cut time"));
7596 XMLNode& after (_session->locations()->get_state());
7597 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7602 XMLNode& before (_session->tempo_map().get_state());
7604 if (_session->tempo_map().remove_time (pos, frames) ) {
7606 begin_reversible_command (_("remove time"));
7609 XMLNode& after (_session->tempo_map().get_state());
7610 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7615 commit_reversible_command ();
7620 Editor::fit_selection ()
7622 if (!selection->tracks.empty()) {
7623 fit_tracks (selection->tracks);
7627 /* no selected tracks - use tracks with selected regions */
7629 if (!selection->regions.empty()) {
7630 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7631 tvl.push_back (&(*r)->get_time_axis_view ());
7637 } else if (internal_editing()) {
7638 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7641 if (entered_track) {
7642 tvl.push_back (entered_track);
7651 Editor::fit_tracks (TrackViewList & tracks)
7653 if (tracks.empty()) {
7657 uint32_t child_heights = 0;
7658 int visible_tracks = 0;
7660 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7662 if (!(*t)->marked_for_display()) {
7666 child_heights += (*t)->effective_height() - (*t)->current_height();
7670 /* compute the per-track height from:
7672 total canvas visible height -
7673 height that will be taken by visible children of selected
7674 tracks - height of the ruler/hscroll area
7676 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7677 double first_y_pos = DBL_MAX;
7679 if (h < TimeAxisView::preset_height (HeightSmall)) {
7680 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7681 /* too small to be displayed */
7685 undo_visual_stack.push_back (current_visual_state (true));
7686 PBD::Unwinder<bool> nsv (no_save_visual, true);
7688 /* build a list of all tracks, including children */
7691 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7693 TimeAxisView::Children c = (*i)->get_child_list ();
7694 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7695 all.push_back (j->get());
7700 // find selection range.
7701 // if someone knows how to user TrackViewList::iterator for this
7703 int selected_top = -1;
7704 int selected_bottom = -1;
7706 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7707 if ((*t)->marked_for_display ()) {
7708 if (tracks.contains(*t)) {
7709 if (selected_top == -1) {
7712 selected_bottom = i;
7718 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7719 if ((*t)->marked_for_display ()) {
7720 if (tracks.contains(*t)) {
7721 (*t)->set_height (h);
7722 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7724 if (i > selected_top && i < selected_bottom) {
7725 hide_track_in_display (*t);
7732 set the controls_layout height now, because waiting for its size
7733 request signal handler will cause the vertical adjustment setting to fail
7736 controls_layout.property_height () = _full_canvas_height;
7737 vertical_adjustment.set_value (first_y_pos);
7739 redo_visual_stack.push_back (current_visual_state (true));
7741 visible_tracks_selector.set_text (_("Sel"));
7745 Editor::save_visual_state (uint32_t n)
7747 while (visual_states.size() <= n) {
7748 visual_states.push_back (0);
7751 if (visual_states[n] != 0) {
7752 delete visual_states[n];
7755 visual_states[n] = current_visual_state (true);
7760 Editor::goto_visual_state (uint32_t n)
7762 if (visual_states.size() <= n) {
7766 if (visual_states[n] == 0) {
7770 use_visual_state (*visual_states[n]);
7774 Editor::start_visual_state_op (uint32_t n)
7776 save_visual_state (n);
7778 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7780 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7781 pup->set_text (buf);
7786 Editor::cancel_visual_state_op (uint32_t n)
7788 goto_visual_state (n);
7792 Editor::toggle_region_mute ()
7794 if (_ignore_region_action) {
7798 RegionSelection rs = get_regions_from_selection_and_entered ();
7804 if (rs.size() > 1) {
7805 begin_reversible_command (_("mute regions"));
7807 begin_reversible_command (_("mute region"));
7810 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7812 (*i)->region()->playlist()->clear_changes ();
7813 (*i)->region()->set_muted (!(*i)->region()->muted ());
7814 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7818 commit_reversible_command ();
7822 Editor::combine_regions ()
7824 /* foreach track with selected regions, take all selected regions
7825 and join them into a new region containing the subregions (as a
7829 typedef set<RouteTimeAxisView*> RTVS;
7832 if (selection->regions.empty()) {
7836 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7837 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7840 tracks.insert (rtv);
7844 begin_reversible_command (_("combine regions"));
7846 vector<RegionView*> new_selection;
7848 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7851 if ((rv = (*i)->combine_regions ()) != 0) {
7852 new_selection.push_back (rv);
7856 selection->clear_regions ();
7857 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7858 selection->add (*i);
7861 commit_reversible_command ();
7865 Editor::uncombine_regions ()
7867 typedef set<RouteTimeAxisView*> RTVS;
7870 if (selection->regions.empty()) {
7874 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7875 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7878 tracks.insert (rtv);
7882 begin_reversible_command (_("uncombine regions"));
7884 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7885 (*i)->uncombine_regions ();
7888 commit_reversible_command ();
7892 Editor::toggle_midi_input_active (bool flip_others)
7895 boost::shared_ptr<RouteList> rl (new RouteList);
7897 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7898 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7904 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7907 rl->push_back (rtav->route());
7908 onoff = !mt->input_active();
7912 _session->set_exclusive_input_active (rl, onoff, flip_others);
7919 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7921 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7922 lock_dialog->get_vbox()->pack_start (*padlock);
7924 ArdourButton* b = manage (new ArdourButton);
7925 b->set_name ("lock button");
7926 b->set_text (_("Click to unlock"));
7927 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7928 lock_dialog->get_vbox()->pack_start (*b);
7930 lock_dialog->get_vbox()->show_all ();
7931 lock_dialog->set_size_request (200, 200);
7934 delete _main_menu_disabler;
7935 _main_menu_disabler = new MainMenuDisabler;
7937 lock_dialog->present ();
7943 lock_dialog->hide ();
7945 delete _main_menu_disabler;
7947 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7948 start_lock_event_timing ();
7953 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7955 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7959 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7961 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7962 Gtkmm2ext::UI::instance()->flush_pending ();
7966 Editor::bring_all_sources_into_session ()
7973 ArdourDialog w (_("Moving embedded files into session folder"));
7974 w.get_vbox()->pack_start (msg);
7977 /* flush all pending GUI events because we're about to start copying
7981 Gtkmm2ext::UI::instance()->flush_pending ();
7985 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));