2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
60 #include "ardour/transpose.h"
62 #include "canvas/canvas.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_remove_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
100 #include "transpose_dialog.h"
101 #include "transform_dialog.h"
102 #include "ui_config.h"
107 using namespace ARDOUR;
110 using namespace Gtkmm2ext;
111 using namespace Editing;
112 using Gtkmm2ext::Keyboard;
114 /***********************************************************************
116 ***********************************************************************/
119 Editor::undo (uint32_t n)
121 if (_drags->active ()) {
127 if (_session->undo_depth() == 0) {
128 undo_action->set_sensitive(false);
130 redo_action->set_sensitive(true);
131 begin_selection_op_history ();
136 Editor::redo (uint32_t n)
138 if (_drags->active ()) {
144 if (_session->redo_depth() == 0) {
145 redo_action->set_sensitive(false);
147 undo_action->set_sensitive(true);
148 begin_selection_op_history ();
153 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
157 RegionSelection pre_selected_regions = selection->regions;
158 bool working_on_selection = !pre_selected_regions.empty();
160 list<boost::shared_ptr<Playlist> > used_playlists;
161 list<RouteTimeAxisView*> used_trackviews;
163 if (regions.empty()) {
167 begin_reversible_command (_("split"));
169 // if splitting a single region, and snap-to is using
170 // region boundaries, don't pay attention to them
172 if (regions.size() == 1) {
173 switch (_snap_type) {
174 case SnapToRegionStart:
175 case SnapToRegionSync:
176 case SnapToRegionEnd:
185 EditorFreeze(); /* Emit Signal */
188 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
190 RegionSelection::iterator tmp;
192 /* XXX this test needs to be more complicated, to make sure we really
193 have something to split.
196 if (!(*a)->region()->covers (where)) {
204 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
212 /* we haven't seen this playlist before */
214 /* remember used playlists so we can thaw them later */
215 used_playlists.push_back(pl);
217 TimeAxisView& tv = (*a)->get_time_axis_view();
218 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
220 used_trackviews.push_back (rtv);
227 pl->clear_changes ();
228 pl->split_region ((*a)->region(), where);
229 _session->add_command (new StatefulDiffCommand (pl));
235 latest_regionviews.clear ();
237 vector<sigc::connection> region_added_connections;
239 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
240 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
243 while (used_playlists.size() > 0) {
244 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
246 used_playlists.pop_front();
249 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
254 EditorThaw(); /* Emit Signal */
257 if (working_on_selection) {
258 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
260 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
261 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
262 /* There are three classes of regions that we might want selected after
263 splitting selected regions:
264 - regions selected before the split operation, and unaffected by it
265 - newly-created regions before the split
266 - newly-created regions after the split
269 if (rsas & Existing) {
270 // region selections that existed before the split.
271 selection->add ( pre_selected_regions );
274 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
275 if ((*ri)->region()->position() < where) {
276 // new regions created before the split
277 if (rsas & NewlyCreatedLeft) {
278 selection->add (*ri);
281 // new regions created after the split
282 if (rsas & NewlyCreatedRight) {
283 selection->add (*ri);
287 _ignore_follow_edits = false;
289 _ignore_follow_edits = true;
290 if( working_on_selection ) {
291 selection->add (latest_regionviews); //these are the new regions created after the split
293 _ignore_follow_edits = false;
296 commit_reversible_command ();
299 /** Move one extreme of the current range selection. If more than one range is selected,
300 * the start of the earliest range or the end of the latest range is moved.
302 * @param move_end true to move the end of the current range selection, false to move
304 * @param next true to move the extreme to the next region boundary, false to move to
308 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
310 if (selection->time.start() == selection->time.end_frame()) {
314 framepos_t start = selection->time.start ();
315 framepos_t end = selection->time.end_frame ();
317 /* the position of the thing we may move */
318 framepos_t pos = move_end ? end : start;
319 int dir = next ? 1 : -1;
321 /* so we don't find the current region again */
322 if (dir > 0 || pos > 0) {
326 framepos_t const target = get_region_boundary (pos, dir, true, false);
341 begin_reversible_selection_op (_("alter selection"));
342 selection->set_preserving_all_ranges (start, end);
343 commit_reversible_selection_op ();
347 Editor::nudge_forward_release (GdkEventButton* ev)
349 if (ev->state & Keyboard::PrimaryModifier) {
350 nudge_forward (false, true);
352 nudge_forward (false, false);
358 Editor::nudge_backward_release (GdkEventButton* ev)
360 if (ev->state & Keyboard::PrimaryModifier) {
361 nudge_backward (false, true);
363 nudge_backward (false, false);
370 Editor::nudge_forward (bool next, bool force_playhead)
373 framepos_t next_distance;
379 RegionSelection rs = get_regions_from_selection_and_entered ();
381 if (!force_playhead && !rs.empty()) {
383 begin_reversible_command (_("nudge regions forward"));
385 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
386 boost::shared_ptr<Region> r ((*i)->region());
388 distance = get_nudge_distance (r->position(), next_distance);
391 distance = next_distance;
395 r->set_position (r->position() + distance);
396 _session->add_command (new StatefulDiffCommand (r));
399 commit_reversible_command ();
402 } else if (!force_playhead && !selection->markers.empty()) {
405 bool in_command = false;
407 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
409 Location* loc = find_location_from_marker ((*i), is_start);
413 XMLNode& before (loc->get_state());
416 distance = get_nudge_distance (loc->start(), next_distance);
418 distance = next_distance;
420 if (max_framepos - distance > loc->start() + loc->length()) {
421 loc->set_start (loc->start() + distance);
423 loc->set_start (max_framepos - loc->length());
426 distance = get_nudge_distance (loc->end(), next_distance);
428 distance = next_distance;
430 if (max_framepos - distance > loc->end()) {
431 loc->set_end (loc->end() + distance);
433 loc->set_end (max_framepos);
437 begin_reversible_command (_("nudge location forward"));
440 XMLNode& after (loc->get_state());
441 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
446 commit_reversible_command ();
449 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
450 _session->request_locate (playhead_cursor->current_frame () + distance);
455 Editor::nudge_backward (bool next, bool force_playhead)
458 framepos_t next_distance;
464 RegionSelection rs = get_regions_from_selection_and_entered ();
466 if (!force_playhead && !rs.empty()) {
468 begin_reversible_command (_("nudge regions backward"));
470 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
471 boost::shared_ptr<Region> r ((*i)->region());
473 distance = get_nudge_distance (r->position(), next_distance);
476 distance = next_distance;
481 if (r->position() > distance) {
482 r->set_position (r->position() - distance);
486 _session->add_command (new StatefulDiffCommand (r));
489 commit_reversible_command ();
491 } else if (!force_playhead && !selection->markers.empty()) {
494 bool in_command = false;
496 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
498 Location* loc = find_location_from_marker ((*i), is_start);
502 XMLNode& before (loc->get_state());
505 distance = get_nudge_distance (loc->start(), next_distance);
507 distance = next_distance;
509 if (distance < loc->start()) {
510 loc->set_start (loc->start() - distance);
515 distance = get_nudge_distance (loc->end(), next_distance);
518 distance = next_distance;
521 if (distance < loc->end() - loc->length()) {
522 loc->set_end (loc->end() - distance);
524 loc->set_end (loc->length());
528 begin_reversible_command (_("nudge location forward"));
531 XMLNode& after (loc->get_state());
532 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
536 commit_reversible_command ();
541 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
543 if (playhead_cursor->current_frame () > distance) {
544 _session->request_locate (playhead_cursor->current_frame () - distance);
546 _session->goto_start();
552 Editor::nudge_forward_capture_offset ()
554 RegionSelection rs = get_regions_from_selection_and_entered ();
556 if (!_session || rs.empty()) {
560 begin_reversible_command (_("nudge forward"));
562 framepos_t const distance = _session->worst_output_latency();
564 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
565 boost::shared_ptr<Region> r ((*i)->region());
568 r->set_position (r->position() + distance);
569 _session->add_command(new StatefulDiffCommand (r));
572 commit_reversible_command ();
576 Editor::nudge_backward_capture_offset ()
578 RegionSelection rs = get_regions_from_selection_and_entered ();
580 if (!_session || rs.empty()) {
584 begin_reversible_command (_("nudge backward"));
586 framepos_t const distance = _session->worst_output_latency();
588 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
589 boost::shared_ptr<Region> r ((*i)->region());
593 if (r->position() > distance) {
594 r->set_position (r->position() - distance);
598 _session->add_command(new StatefulDiffCommand (r));
601 commit_reversible_command ();
604 struct RegionSelectionPositionSorter {
605 bool operator() (RegionView* a, RegionView* b) {
606 return a->region()->position() < b->region()->position();
611 Editor::sequence_regions ()
614 framepos_t r_end_prev;
622 RegionSelection rs = get_regions_from_selection_and_entered ();
623 rs.sort(RegionSelectionPositionSorter());
627 bool in_command = false;
629 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
630 boost::shared_ptr<Region> r ((*i)->region());
638 if(r->position_locked())
645 r->set_position(r_end_prev);
649 begin_reversible_command (_("sequence regions"));
652 _session->add_command (new StatefulDiffCommand (r));
654 r_end=r->position() + r->length();
660 commit_reversible_command ();
669 Editor::move_to_start ()
671 _session->goto_start ();
675 Editor::move_to_end ()
678 _session->request_locate (_session->current_end_frame());
682 Editor::build_region_boundary_cache ()
685 vector<RegionPoint> interesting_points;
686 boost::shared_ptr<Region> r;
687 TrackViewList tracks;
690 region_boundary_cache.clear ();
696 switch (_snap_type) {
697 case SnapToRegionStart:
698 interesting_points.push_back (Start);
700 case SnapToRegionEnd:
701 interesting_points.push_back (End);
703 case SnapToRegionSync:
704 interesting_points.push_back (SyncPoint);
706 case SnapToRegionBoundary:
707 interesting_points.push_back (Start);
708 interesting_points.push_back (End);
711 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
712 abort(); /*NOTREACHED*/
716 TimeAxisView *ontrack = 0;
719 if (!selection->tracks.empty()) {
720 tlist = selection->tracks.filter_to_unique_playlists ();
722 tlist = track_views.filter_to_unique_playlists ();
725 while (pos < _session->current_end_frame() && !at_end) {
728 framepos_t lpos = max_framepos;
730 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
732 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
733 if (*p == interesting_points.back()) {
736 /* move to next point type */
742 rpos = r->first_frame();
746 rpos = r->last_frame();
750 rpos = r->sync_position ();
758 RouteTimeAxisView *rtav;
760 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
761 if (rtav->track() != 0) {
762 speed = rtav->track()->speed();
766 rpos = track_frame_to_session_frame (rpos, speed);
772 /* prevent duplicates, but we don't use set<> because we want to be able
776 vector<framepos_t>::iterator ri;
778 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
784 if (ri == region_boundary_cache.end()) {
785 region_boundary_cache.push_back (rpos);
792 /* finally sort to be sure that the order is correct */
794 sort (region_boundary_cache.begin(), region_boundary_cache.end());
797 boost::shared_ptr<Region>
798 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
800 TrackViewList::iterator i;
801 framepos_t closest = max_framepos;
802 boost::shared_ptr<Region> ret;
806 framepos_t track_frame;
807 RouteTimeAxisView *rtav;
809 for (i = tracks.begin(); i != tracks.end(); ++i) {
812 boost::shared_ptr<Region> r;
815 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
816 if (rtav->track()!=0)
817 track_speed = rtav->track()->speed();
820 track_frame = session_frame_to_track_frame(frame, track_speed);
822 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
828 rpos = r->first_frame ();
832 rpos = r->last_frame ();
836 rpos = r->sync_position ();
840 // rpos is a "track frame", converting it to "_session frame"
841 rpos = track_frame_to_session_frame(rpos, track_speed);
844 distance = rpos - frame;
846 distance = frame - rpos;
849 if (distance < closest) {
861 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
863 framecnt_t distance = max_framepos;
864 framepos_t current_nearest = -1;
866 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
867 framepos_t contender;
870 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
876 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
880 d = ::llabs (pos - contender);
883 current_nearest = contender;
888 return current_nearest;
892 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
897 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
899 if (!selection->tracks.empty()) {
901 target = find_next_region_boundary (pos, dir, selection->tracks);
905 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
906 get_onscreen_tracks (tvl);
907 target = find_next_region_boundary (pos, dir, tvl);
909 target = find_next_region_boundary (pos, dir, track_views);
915 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
916 get_onscreen_tracks (tvl);
917 target = find_next_region_boundary (pos, dir, tvl);
919 target = find_next_region_boundary (pos, dir, track_views);
927 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
929 framepos_t pos = playhead_cursor->current_frame ();
936 // so we don't find the current region again..
937 if (dir > 0 || pos > 0) {
941 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
945 _session->request_locate (target);
949 Editor::cursor_to_next_region_boundary (bool with_selection)
951 cursor_to_region_boundary (with_selection, 1);
955 Editor::cursor_to_previous_region_boundary (bool with_selection)
957 cursor_to_region_boundary (with_selection, -1);
961 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
963 boost::shared_ptr<Region> r;
964 framepos_t pos = cursor->current_frame ();
970 TimeAxisView *ontrack = 0;
972 // so we don't find the current region again..
976 if (!selection->tracks.empty()) {
978 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
980 } else if (clicked_axisview) {
983 t.push_back (clicked_axisview);
985 r = find_next_region (pos, point, dir, t, &ontrack);
989 r = find_next_region (pos, point, dir, track_views, &ontrack);
998 pos = r->first_frame ();
1002 pos = r->last_frame ();
1006 pos = r->sync_position ();
1011 RouteTimeAxisView *rtav;
1013 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1014 if (rtav->track() != 0) {
1015 speed = rtav->track()->speed();
1019 pos = track_frame_to_session_frame(pos, speed);
1021 if (cursor == playhead_cursor) {
1022 _session->request_locate (pos);
1024 cursor->set_position (pos);
1029 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1031 cursor_to_region_point (cursor, point, 1);
1035 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1037 cursor_to_region_point (cursor, point, -1);
1041 Editor::cursor_to_selection_start (EditorCursor *cursor)
1045 switch (mouse_mode) {
1047 if (!selection->regions.empty()) {
1048 pos = selection->regions.start();
1053 if (!selection->time.empty()) {
1054 pos = selection->time.start ();
1062 if (cursor == playhead_cursor) {
1063 _session->request_locate (pos);
1065 cursor->set_position (pos);
1070 Editor::cursor_to_selection_end (EditorCursor *cursor)
1074 switch (mouse_mode) {
1076 if (!selection->regions.empty()) {
1077 pos = selection->regions.end_frame();
1082 if (!selection->time.empty()) {
1083 pos = selection->time.end_frame ();
1091 if (cursor == playhead_cursor) {
1092 _session->request_locate (pos);
1094 cursor->set_position (pos);
1099 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1109 if (selection->markers.empty()) {
1113 if (!mouse_frame (mouse, ignored)) {
1117 add_location_mark (mouse);
1120 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1124 framepos_t pos = loc->start();
1126 // so we don't find the current region again..
1127 if (dir > 0 || pos > 0) {
1131 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1135 loc->move_to (target);
1139 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1141 selected_marker_to_region_boundary (with_selection, 1);
1145 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1147 selected_marker_to_region_boundary (with_selection, -1);
1151 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1153 boost::shared_ptr<Region> r;
1158 if (!_session || selection->markers.empty()) {
1162 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1166 TimeAxisView *ontrack = 0;
1170 // so we don't find the current region again..
1174 if (!selection->tracks.empty()) {
1176 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1180 r = find_next_region (pos, point, dir, track_views, &ontrack);
1189 pos = r->first_frame ();
1193 pos = r->last_frame ();
1197 pos = r->adjust_to_sync (r->first_frame());
1202 RouteTimeAxisView *rtav;
1204 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1205 if (rtav->track() != 0) {
1206 speed = rtav->track()->speed();
1210 pos = track_frame_to_session_frame(pos, speed);
1216 Editor::selected_marker_to_next_region_point (RegionPoint point)
1218 selected_marker_to_region_point (point, 1);
1222 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1224 selected_marker_to_region_point (point, -1);
1228 Editor::selected_marker_to_selection_start ()
1234 if (!_session || selection->markers.empty()) {
1238 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1242 switch (mouse_mode) {
1244 if (!selection->regions.empty()) {
1245 pos = selection->regions.start();
1250 if (!selection->time.empty()) {
1251 pos = selection->time.start ();
1263 Editor::selected_marker_to_selection_end ()
1269 if (!_session || selection->markers.empty()) {
1273 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1277 switch (mouse_mode) {
1279 if (!selection->regions.empty()) {
1280 pos = selection->regions.end_frame();
1285 if (!selection->time.empty()) {
1286 pos = selection->time.end_frame ();
1298 Editor::scroll_playhead (bool forward)
1300 framepos_t pos = playhead_cursor->current_frame ();
1301 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1304 if (pos == max_framepos) {
1308 if (pos < max_framepos - delta) {
1327 _session->request_locate (pos);
1331 Editor::cursor_align (bool playhead_to_edit)
1337 if (playhead_to_edit) {
1339 if (selection->markers.empty()) {
1343 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1346 /* move selected markers to playhead */
1348 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1351 Location* loc = find_location_from_marker (*i, ignored);
1353 if (loc->is_mark()) {
1354 loc->set_start (playhead_cursor->current_frame ());
1356 loc->set (playhead_cursor->current_frame (),
1357 playhead_cursor->current_frame () + loc->length());
1364 Editor::scroll_backward (float pages)
1366 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1367 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1370 if (leftmost_frame < cnt) {
1373 frame = leftmost_frame - cnt;
1376 reset_x_origin (frame);
1380 Editor::scroll_forward (float pages)
1382 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1383 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1386 if (max_framepos - cnt < leftmost_frame) {
1387 frame = max_framepos - cnt;
1389 frame = leftmost_frame + cnt;
1392 reset_x_origin (frame);
1396 Editor::scroll_tracks_down ()
1398 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1399 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1400 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1403 vertical_adjustment.set_value (vert_value);
1407 Editor::scroll_tracks_up ()
1409 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1413 Editor::scroll_tracks_down_line ()
1415 double vert_value = vertical_adjustment.get_value() + 60;
1417 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1418 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1421 vertical_adjustment.set_value (vert_value);
1425 Editor::scroll_tracks_up_line ()
1427 reset_y_origin (vertical_adjustment.get_value() - 60);
1431 Editor::scroll_down_one_track (bool skip_child_views)
1433 TrackViewList::reverse_iterator next = track_views.rend();
1434 const double top_of_trackviews = vertical_adjustment.get_value();
1436 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1437 if ((*t)->hidden()) {
1441 /* If this is the upper-most visible trackview, we want to display
1442 * the one above it (next)
1444 * Note that covers_y_position() is recursive and includes child views
1446 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1449 if (skip_child_views) {
1452 /* automation lane (one level, non-recursive)
1454 * - if no automation lane exists -> move to next tack
1455 * - if the first (here: bottom-most) matches -> move to next tack
1456 * - if no y-axis match is found -> the current track is at the top
1457 * -> move to last (here: top-most) automation lane
1459 TimeAxisView::Children kids = (*t)->get_child_list();
1460 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1462 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1463 if ((*ci)->hidden()) {
1467 std::pair<TimeAxisView*,double> dev;
1468 dev = (*ci)->covers_y_position (top_of_trackviews);
1470 /* some automation lane is currently at the top */
1471 if (ci == kids.rbegin()) {
1472 /* first (bottom-most) autmation lane is at the top.
1473 * -> move to next track
1482 if (nkid != kids.rend()) {
1483 ensure_time_axis_view_is_visible (**nkid, true);
1491 /* move to the track below the first one that covers the */
1493 if (next != track_views.rend()) {
1494 ensure_time_axis_view_is_visible (**next, true);
1502 Editor::scroll_up_one_track (bool skip_child_views)
1504 TrackViewList::iterator prev = track_views.end();
1505 double top_of_trackviews = vertical_adjustment.get_value ();
1507 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1509 if ((*t)->hidden()) {
1513 /* find the trackview at the top of the trackview group
1515 * Note that covers_y_position() is recursive and includes child views
1517 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1520 if (skip_child_views) {
1523 /* automation lane (one level, non-recursive)
1525 * - if no automation lane exists -> move to prev tack
1526 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1527 * (actually last automation lane of previous track, see below)
1528 * - if first (top-most) lane is at the top -> move to this track
1529 * - else move up one lane
1531 TimeAxisView::Children kids = (*t)->get_child_list();
1532 TimeAxisView::Children::iterator pkid = kids.end();
1534 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1535 if ((*ci)->hidden()) {
1539 std::pair<TimeAxisView*,double> dev;
1540 dev = (*ci)->covers_y_position (top_of_trackviews);
1542 /* some automation lane is currently at the top */
1543 if (ci == kids.begin()) {
1544 /* first (top-most) autmation lane is at the top.
1545 * jump directly to this track's top
1547 ensure_time_axis_view_is_visible (**t, true);
1550 else if (pkid != kids.end()) {
1551 /* some other automation lane is at the top.
1552 * move up to prev automation lane.
1554 ensure_time_axis_view_is_visible (**pkid, true);
1557 assert(0); // not reached
1568 if (prev != track_views.end()) {
1569 // move to bottom-most automation-lane of the previous track
1570 TimeAxisView::Children kids = (*prev)->get_child_list();
1571 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1572 if (!skip_child_views) {
1573 // find the last visible lane
1574 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1575 if (!(*ci)->hidden()) {
1581 if (pkid != kids.rend()) {
1582 ensure_time_axis_view_is_visible (**pkid, true);
1584 ensure_time_axis_view_is_visible (**prev, true);
1595 Editor::tav_zoom_step (bool coarser)
1597 DisplaySuspender ds;
1601 if (selection->tracks.empty()) {
1604 ts = &selection->tracks;
1607 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1608 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1609 tv->step_height (coarser);
1614 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1616 DisplaySuspender ds;
1620 if (selection->tracks.empty() || force_all) {
1623 ts = &selection->tracks;
1626 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1627 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1628 uint32_t h = tv->current_height ();
1633 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1638 tv->set_height (h + 5);
1645 Editor::temporal_zoom_step (bool coarser)
1647 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1649 framecnt_t nspp = samples_per_pixel;
1657 temporal_zoom (nspp);
1661 Editor::temporal_zoom (framecnt_t fpp)
1667 framepos_t current_page = current_page_samples();
1668 framepos_t current_leftmost = leftmost_frame;
1669 framepos_t current_rightmost;
1670 framepos_t current_center;
1671 framepos_t new_page_size;
1672 framepos_t half_page_size;
1673 framepos_t leftmost_after_zoom = 0;
1675 bool in_track_canvas;
1679 if (fpp == samples_per_pixel) {
1683 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1684 // segfaults for lack of memory. If somebody decides this is not high enough I
1685 // believe it can be raisen to higher values but some limit must be in place.
1687 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1688 // all of which is used for the editor track displays. The whole day
1689 // would be 4147200000 samples, so 2592000 samples per pixel.
1691 nfpp = min (fpp, (framecnt_t) 2592000);
1692 nfpp = max ((framecnt_t) 1, nfpp);
1694 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1695 half_page_size = new_page_size / 2;
1697 switch (zoom_focus) {
1699 leftmost_after_zoom = current_leftmost;
1702 case ZoomFocusRight:
1703 current_rightmost = leftmost_frame + current_page;
1704 if (current_rightmost < new_page_size) {
1705 leftmost_after_zoom = 0;
1707 leftmost_after_zoom = current_rightmost - new_page_size;
1711 case ZoomFocusCenter:
1712 current_center = current_leftmost + (current_page/2);
1713 if (current_center < half_page_size) {
1714 leftmost_after_zoom = 0;
1716 leftmost_after_zoom = current_center - half_page_size;
1720 case ZoomFocusPlayhead:
1721 /* centre playhead */
1722 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1725 leftmost_after_zoom = 0;
1726 } else if (l > max_framepos) {
1727 leftmost_after_zoom = max_framepos - new_page_size;
1729 leftmost_after_zoom = (framepos_t) l;
1733 case ZoomFocusMouse:
1734 /* try to keep the mouse over the same point in the display */
1736 if (!mouse_frame (where, in_track_canvas)) {
1737 /* use playhead instead */
1738 where = playhead_cursor->current_frame ();
1740 if (where < half_page_size) {
1741 leftmost_after_zoom = 0;
1743 leftmost_after_zoom = where - half_page_size;
1748 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1751 leftmost_after_zoom = 0;
1752 } else if (l > max_framepos) {
1753 leftmost_after_zoom = max_framepos - new_page_size;
1755 leftmost_after_zoom = (framepos_t) l;
1762 /* try to keep the edit point in the same place */
1763 where = get_preferred_edit_position ();
1767 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1770 leftmost_after_zoom = 0;
1771 } else if (l > max_framepos) {
1772 leftmost_after_zoom = max_framepos - new_page_size;
1774 leftmost_after_zoom = (framepos_t) l;
1778 /* edit point not defined */
1785 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1787 reposition_and_zoom (leftmost_after_zoom, nfpp);
1791 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1793 /* this func helps make sure we leave a little space
1794 at each end of the editor so that the zoom doesn't fit the region
1795 precisely to the screen.
1798 GdkScreen* screen = gdk_screen_get_default ();
1799 const gint pixwidth = gdk_screen_get_width (screen);
1800 const gint mmwidth = gdk_screen_get_width_mm (screen);
1801 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1802 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1804 const framepos_t range = end - start;
1805 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1806 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1808 if (start > extra_samples) {
1809 start -= extra_samples;
1814 if (max_framepos - extra_samples > end) {
1815 end += extra_samples;
1822 Editor::temporal_zoom_region (bool both_axes)
1824 framepos_t start = max_framepos;
1826 set<TimeAxisView*> tracks;
1828 if ( !get_selection_extents(start, end) )
1831 calc_extra_zoom_edges (start, end);
1833 /* if we're zooming on both axes we need to save track heights etc.
1836 undo_visual_stack.push_back (current_visual_state (both_axes));
1838 PBD::Unwinder<bool> nsv (no_save_visual, true);
1840 temporal_zoom_by_frame (start, end);
1843 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1845 /* set visible track heights appropriately */
1847 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1848 (*t)->set_height (per_track_height);
1851 /* hide irrelevant tracks */
1853 DisplaySuspender ds;
1855 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1856 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1857 hide_track_in_display (*i);
1861 vertical_adjustment.set_value (0.0);
1864 redo_visual_stack.push_back (current_visual_state (both_axes));
1869 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1871 start = max_framepos;
1875 //ToDo: if notes are selected, set extents to that selection
1877 //ToDo: if control points are selected, set extents to that selection
1879 if ( !selection->regions.empty() ) {
1880 RegionSelection rs = get_regions_from_selection_and_entered ();
1882 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1884 if ((*i)->region()->position() < start) {
1885 start = (*i)->region()->position();
1888 if ((*i)->region()->last_frame() + 1 > end) {
1889 end = (*i)->region()->last_frame() + 1;
1893 } else if (!selection->time.empty()) {
1894 start = selection->time.start();
1895 end = selection->time.end_frame();
1897 ret = false; //no selection found
1900 if ((start == 0 && end == 0) || end < start) {
1909 Editor::temporal_zoom_selection (bool both_axes)
1911 if (!selection) return;
1913 //ToDo: if notes are selected, zoom to that
1915 //ToDo: if control points are selected, zoom to that
1917 //if region(s) are selected, zoom to that
1918 if ( !selection->regions.empty() )
1919 temporal_zoom_region (both_axes);
1921 //if a range is selected, zoom to that
1922 if (!selection->time.empty()) {
1924 framepos_t start, end;
1925 if (get_selection_extents (start, end)) {
1926 calc_extra_zoom_edges(start, end);
1927 temporal_zoom_by_frame (start, end);
1937 Editor::temporal_zoom_session ()
1939 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1942 framecnt_t start = _session->current_start_frame();
1943 framecnt_t end = _session->current_end_frame();
1945 if (_session->actively_recording () ) {
1946 framepos_t cur = playhead_cursor->current_frame ();
1948 /* recording beyond the end marker; zoom out
1949 * by 5 seconds more so that if 'follow
1950 * playhead' is active we don't immediately
1953 end = cur + _session->frame_rate() * 5;
1957 if ((start == 0 && end == 0) || end < start) {
1961 calc_extra_zoom_edges(start, end);
1963 temporal_zoom_by_frame (start, end);
1968 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1970 if (!_session) return;
1972 if ((start == 0 && end == 0) || end < start) {
1976 framepos_t range = end - start;
1978 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1980 framepos_t new_page = range;
1981 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1982 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1984 if (new_leftmost > middle) {
1988 if (new_leftmost < 0) {
1992 reposition_and_zoom (new_leftmost, new_fpp);
1996 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2002 framecnt_t range_before = frame - leftmost_frame;
2006 if (samples_per_pixel <= 1) {
2009 new_spp = samples_per_pixel + (samples_per_pixel/2);
2011 range_before += range_before/2;
2013 if (samples_per_pixel >= 1) {
2014 new_spp = samples_per_pixel - (samples_per_pixel/2);
2016 /* could bail out here since we cannot zoom any finer,
2017 but leave that to the equality test below
2019 new_spp = samples_per_pixel;
2022 range_before -= range_before/2;
2025 if (new_spp == samples_per_pixel) {
2029 /* zoom focus is automatically taken as @param frame when this
2033 framepos_t new_leftmost = frame - (framepos_t)range_before;
2035 if (new_leftmost > frame) {
2039 if (new_leftmost < 0) {
2043 reposition_and_zoom (new_leftmost, new_spp);
2048 Editor::choose_new_marker_name(string &name) {
2050 if (!UIConfiguration::instance().get_name_new_markers()) {
2051 /* don't prompt user for a new name */
2055 ArdourPrompter dialog (true);
2057 dialog.set_prompt (_("New Name:"));
2059 dialog.set_title (_("New Location Marker"));
2061 dialog.set_name ("MarkNameWindow");
2062 dialog.set_size_request (250, -1);
2063 dialog.set_position (Gtk::WIN_POS_MOUSE);
2065 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2066 dialog.set_initial_text (name);
2070 switch (dialog.run ()) {
2071 case RESPONSE_ACCEPT:
2077 dialog.get_result(name);
2084 Editor::add_location_from_selection ()
2088 if (selection->time.empty()) {
2092 if (_session == 0 || clicked_axisview == 0) {
2096 framepos_t start = selection->time[clicked_selection].start;
2097 framepos_t end = selection->time[clicked_selection].end;
2099 _session->locations()->next_available_name(rangename,"selection");
2100 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2102 begin_reversible_command (_("add marker"));
2104 XMLNode &before = _session->locations()->get_state();
2105 _session->locations()->add (location, true);
2106 XMLNode &after = _session->locations()->get_state();
2107 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2109 commit_reversible_command ();
2113 Editor::add_location_mark (framepos_t where)
2117 select_new_marker = true;
2119 _session->locations()->next_available_name(markername,"mark");
2120 if (!choose_new_marker_name(markername)) {
2123 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2124 begin_reversible_command (_("add marker"));
2126 XMLNode &before = _session->locations()->get_state();
2127 _session->locations()->add (location, true);
2128 XMLNode &after = _session->locations()->get_state();
2129 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2131 commit_reversible_command ();
2135 Editor::set_session_start_from_playhead ()
2141 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2142 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2144 XMLNode &before = loc->get_state();
2146 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2148 XMLNode &after = loc->get_state();
2150 begin_reversible_command (_("Set session start"));
2152 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2154 commit_reversible_command ();
2159 Editor::set_session_end_from_playhead ()
2165 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2166 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2168 XMLNode &before = loc->get_state();
2170 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2172 XMLNode &after = loc->get_state();
2174 begin_reversible_command (_("Set session start"));
2176 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2178 commit_reversible_command ();
2183 Editor::add_location_from_playhead_cursor ()
2185 add_location_mark (_session->audible_frame());
2189 Editor::remove_location_at_playhead_cursor ()
2193 XMLNode &before = _session->locations()->get_state();
2194 bool removed = false;
2196 //find location(s) at this time
2197 Locations::LocationList locs;
2198 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2199 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2200 if ((*i)->is_mark()) {
2201 _session->locations()->remove (*i);
2208 begin_reversible_command (_("remove marker"));
2209 XMLNode &after = _session->locations()->get_state();
2210 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2211 commit_reversible_command ();
2216 /** Add a range marker around each selected region */
2218 Editor::add_locations_from_region ()
2220 RegionSelection rs = get_regions_from_selection_and_entered ();
2225 bool commit = false;
2227 XMLNode &before = _session->locations()->get_state();
2229 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2231 boost::shared_ptr<Region> region = (*i)->region ();
2233 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2235 _session->locations()->add (location, true);
2240 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2241 XMLNode &after = _session->locations()->get_state();
2242 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2243 commit_reversible_command ();
2247 /** Add a single range marker around all selected regions */
2249 Editor::add_location_from_region ()
2251 RegionSelection rs = get_regions_from_selection_and_entered ();
2257 XMLNode &before = _session->locations()->get_state();
2261 if (rs.size() > 1) {
2262 _session->locations()->next_available_name(markername, "regions");
2264 RegionView* rv = *(rs.begin());
2265 boost::shared_ptr<Region> region = rv->region();
2266 markername = region->name();
2269 if (!choose_new_marker_name(markername)) {
2273 // single range spanning all selected
2274 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2275 _session->locations()->add (location, true);
2277 begin_reversible_command (_("add marker"));
2278 XMLNode &after = _session->locations()->get_state();
2279 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2280 commit_reversible_command ();
2286 Editor::jump_forward_to_mark ()
2292 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2298 _session->request_locate (pos, _session->transport_rolling());
2302 Editor::jump_backward_to_mark ()
2308 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2314 _session->request_locate (pos, _session->transport_rolling());
2320 framepos_t const pos = _session->audible_frame ();
2323 _session->locations()->next_available_name (markername, "mark");
2325 if (!choose_new_marker_name (markername)) {
2329 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2333 Editor::clear_markers ()
2336 begin_reversible_command (_("clear markers"));
2338 XMLNode &before = _session->locations()->get_state();
2339 _session->locations()->clear_markers ();
2340 XMLNode &after = _session->locations()->get_state();
2341 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2343 commit_reversible_command ();
2348 Editor::clear_ranges ()
2351 begin_reversible_command (_("clear ranges"));
2353 XMLNode &before = _session->locations()->get_state();
2355 _session->locations()->clear_ranges ();
2357 XMLNode &after = _session->locations()->get_state();
2358 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2360 commit_reversible_command ();
2365 Editor::clear_locations ()
2367 begin_reversible_command (_("clear locations"));
2369 XMLNode &before = _session->locations()->get_state();
2370 _session->locations()->clear ();
2371 XMLNode &after = _session->locations()->get_state();
2372 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2374 commit_reversible_command ();
2378 Editor::unhide_markers ()
2380 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2381 Location *l = (*i).first;
2382 if (l->is_hidden() && l->is_mark()) {
2383 l->set_hidden(false, this);
2389 Editor::unhide_ranges ()
2391 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2392 Location *l = (*i).first;
2393 if (l->is_hidden() && l->is_range_marker()) {
2394 l->set_hidden(false, this);
2399 /* INSERT/REPLACE */
2402 Editor::insert_region_list_selection (float times)
2404 RouteTimeAxisView *tv = 0;
2405 boost::shared_ptr<Playlist> playlist;
2407 if (clicked_routeview != 0) {
2408 tv = clicked_routeview;
2409 } else if (!selection->tracks.empty()) {
2410 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2413 } else if (entered_track != 0) {
2414 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2421 if ((playlist = tv->playlist()) == 0) {
2425 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2430 begin_reversible_command (_("insert region"));
2431 playlist->clear_changes ();
2432 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2433 if (Config->get_edit_mode() == Ripple)
2434 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2436 _session->add_command(new StatefulDiffCommand (playlist));
2437 commit_reversible_command ();
2440 /* BUILT-IN EFFECTS */
2443 Editor::reverse_selection ()
2448 /* GAIN ENVELOPE EDITING */
2451 Editor::edit_envelope ()
2458 Editor::transition_to_rolling (bool fwd)
2464 if (_session->config.get_external_sync()) {
2465 switch (Config->get_sync_source()) {
2469 /* transport controlled by the master */
2474 if (_session->is_auditioning()) {
2475 _session->cancel_audition ();
2479 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2483 Editor::play_from_start ()
2485 _session->request_locate (_session->current_start_frame(), true);
2489 Editor::play_from_edit_point ()
2491 _session->request_locate (get_preferred_edit_position(), true);
2495 Editor::play_from_edit_point_and_return ()
2497 framepos_t start_frame;
2498 framepos_t return_frame;
2500 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2502 if (_session->transport_rolling()) {
2503 _session->request_locate (start_frame, false);
2507 /* don't reset the return frame if its already set */
2509 if ((return_frame = _session->requested_return_frame()) < 0) {
2510 return_frame = _session->audible_frame();
2513 if (start_frame >= 0) {
2514 _session->request_roll_at_and_return (start_frame, return_frame);
2519 Editor::play_selection ()
2521 framepos_t start, end;
2522 if (!get_selection_extents ( start, end))
2525 AudioRange ar (start, end, 0);
2526 list<AudioRange> lar;
2529 _session->request_play_range (&lar, true);
2533 Editor::get_preroll ()
2535 return Config->get_preroll_seconds() * _session->frame_rate();
2540 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2542 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2545 location -= get_preroll();
2547 //don't try to locate before the beginning of time
2551 //if follow_playhead is on, keep the playhead on the screen
2552 if ( _follow_playhead )
2553 if ( location < leftmost_frame )
2554 location = leftmost_frame;
2556 _session->request_locate( location );
2560 Editor::play_with_preroll ()
2563 framepos_t preroll = get_preroll();
2565 framepos_t start, end;
2566 if (!get_selection_extents ( start, end))
2569 if (start > preroll)
2570 start = start - preroll;
2572 end = end + preroll; //"post-roll"
2574 AudioRange ar (start, end, 0);
2575 list<AudioRange> lar;
2578 _session->request_play_range (&lar, true);
2583 Editor::play_location (Location& location)
2585 if (location.start() <= location.end()) {
2589 _session->request_bounded_roll (location.start(), location.end());
2593 Editor::loop_location (Location& location)
2595 if (location.start() <= location.end()) {
2601 if ((tll = transport_loop_location()) != 0) {
2602 tll->set (location.start(), location.end());
2604 // enable looping, reposition and start rolling
2605 _session->request_locate (tll->start(), true);
2606 _session->request_play_loop (true);
2611 Editor::do_layer_operation (LayerOperation op)
2613 if (selection->regions.empty ()) {
2617 bool const multiple = selection->regions.size() > 1;
2621 begin_reversible_command (_("raise regions"));
2623 begin_reversible_command (_("raise region"));
2629 begin_reversible_command (_("raise regions to top"));
2631 begin_reversible_command (_("raise region to top"));
2637 begin_reversible_command (_("lower regions"));
2639 begin_reversible_command (_("lower region"));
2645 begin_reversible_command (_("lower regions to bottom"));
2647 begin_reversible_command (_("lower region"));
2652 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2653 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2654 (*i)->clear_owned_changes ();
2657 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2658 boost::shared_ptr<Region> r = (*i)->region ();
2670 r->lower_to_bottom ();
2674 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2675 vector<Command*> cmds;
2677 _session->add_commands (cmds);
2680 commit_reversible_command ();
2684 Editor::raise_region ()
2686 do_layer_operation (Raise);
2690 Editor::raise_region_to_top ()
2692 do_layer_operation (RaiseToTop);
2696 Editor::lower_region ()
2698 do_layer_operation (Lower);
2702 Editor::lower_region_to_bottom ()
2704 do_layer_operation (LowerToBottom);
2707 /** Show the region editor for the selected regions */
2709 Editor::show_region_properties ()
2711 selection->foreach_regionview (&RegionView::show_region_editor);
2714 /** Show the midi list editor for the selected MIDI regions */
2716 Editor::show_midi_list_editor ()
2718 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2722 Editor::rename_region ()
2724 RegionSelection rs = get_regions_from_selection_and_entered ();
2730 ArdourDialog d (*this, _("Rename Region"), true, false);
2732 Label label (_("New name:"));
2735 hbox.set_spacing (6);
2736 hbox.pack_start (label, false, false);
2737 hbox.pack_start (entry, true, true);
2739 d.get_vbox()->set_border_width (12);
2740 d.get_vbox()->pack_start (hbox, false, false);
2742 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2743 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2745 d.set_size_request (300, -1);
2747 entry.set_text (rs.front()->region()->name());
2748 entry.select_region (0, -1);
2750 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2756 int const ret = d.run();
2760 if (ret != RESPONSE_OK) {
2764 std::string str = entry.get_text();
2765 strip_whitespace_edges (str);
2767 rs.front()->region()->set_name (str);
2768 _regions->redisplay ();
2772 /** Start an audition of the first selected region */
2774 Editor::play_edit_range ()
2776 framepos_t start, end;
2778 if (get_edit_op_range (start, end)) {
2779 _session->request_bounded_roll (start, end);
2784 Editor::play_selected_region ()
2786 framepos_t start = max_framepos;
2789 RegionSelection rs = get_regions_from_selection_and_entered ();
2795 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2796 if ((*i)->region()->position() < start) {
2797 start = (*i)->region()->position();
2799 if ((*i)->region()->last_frame() + 1 > end) {
2800 end = (*i)->region()->last_frame() + 1;
2804 _session->request_bounded_roll (start, end);
2808 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2810 _session->audition_region (region);
2814 Editor::region_from_selection ()
2816 if (clicked_axisview == 0) {
2820 if (selection->time.empty()) {
2824 framepos_t start = selection->time[clicked_selection].start;
2825 framepos_t end = selection->time[clicked_selection].end;
2827 TrackViewList tracks = get_tracks_for_range_action ();
2829 framepos_t selection_cnt = end - start + 1;
2831 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2832 boost::shared_ptr<Region> current;
2833 boost::shared_ptr<Playlist> pl;
2834 framepos_t internal_start;
2837 if ((pl = (*i)->playlist()) == 0) {
2841 if ((current = pl->top_region_at (start)) == 0) {
2845 internal_start = start - current->position();
2846 RegionFactory::region_name (new_name, current->name(), true);
2850 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2851 plist.add (ARDOUR::Properties::length, selection_cnt);
2852 plist.add (ARDOUR::Properties::name, new_name);
2853 plist.add (ARDOUR::Properties::layer, 0);
2855 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2860 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2862 if (selection->time.empty() || selection->tracks.empty()) {
2866 framepos_t start, end;
2867 if (clicked_selection) {
2868 start = selection->time[clicked_selection].start;
2869 end = selection->time[clicked_selection].end;
2871 start = selection->time.start();
2872 end = selection->time.end_frame();
2875 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2876 sort_track_selection (ts);
2878 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2879 boost::shared_ptr<Region> current;
2880 boost::shared_ptr<Playlist> playlist;
2881 framepos_t internal_start;
2884 if ((playlist = (*i)->playlist()) == 0) {
2888 if ((current = playlist->top_region_at(start)) == 0) {
2892 internal_start = start - current->position();
2893 RegionFactory::region_name (new_name, current->name(), true);
2897 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2898 plist.add (ARDOUR::Properties::length, end - start + 1);
2899 plist.add (ARDOUR::Properties::name, new_name);
2901 new_regions.push_back (RegionFactory::create (current, plist));
2906 Editor::split_multichannel_region ()
2908 RegionSelection rs = get_regions_from_selection_and_entered ();
2914 vector< boost::shared_ptr<Region> > v;
2916 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2917 (*x)->region()->separate_by_channel (*_session, v);
2922 Editor::new_region_from_selection ()
2924 region_from_selection ();
2925 cancel_selection ();
2929 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2931 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2932 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2933 case Evoral::OverlapNone:
2941 * - selected tracks, or if there are none...
2942 * - tracks containing selected regions, or if there are none...
2947 Editor::get_tracks_for_range_action () const
2951 if (selection->tracks.empty()) {
2953 /* use tracks with selected regions */
2955 RegionSelection rs = selection->regions;
2957 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2958 TimeAxisView* tv = &(*i)->get_time_axis_view();
2960 if (!t.contains (tv)) {
2966 /* no regions and no tracks: use all tracks */
2972 t = selection->tracks;
2975 return t.filter_to_unique_playlists();
2979 Editor::separate_regions_between (const TimeSelection& ts)
2981 bool in_command = false;
2982 boost::shared_ptr<Playlist> playlist;
2983 RegionSelection new_selection;
2985 TrackViewList tmptracks = get_tracks_for_range_action ();
2986 sort_track_selection (tmptracks);
2988 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2990 RouteTimeAxisView* rtv;
2992 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2994 if (rtv->is_track()) {
2996 /* no edits to destructive tracks */
2998 if (rtv->track()->destructive()) {
3002 if ((playlist = rtv->playlist()) != 0) {
3004 playlist->clear_changes ();
3006 /* XXX need to consider musical time selections here at some point */
3008 double speed = rtv->track()->speed();
3011 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3013 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3014 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3016 latest_regionviews.clear ();
3018 playlist->partition ((framepos_t)((*t).start * speed),
3019 (framepos_t)((*t).end * speed), false);
3023 if (!latest_regionviews.empty()) {
3025 rtv->view()->foreach_regionview (sigc::bind (
3026 sigc::ptr_fun (add_if_covered),
3027 &(*t), &new_selection));
3030 begin_reversible_command (_("separate"));
3034 /* pick up changes to existing regions */
3036 vector<Command*> cmds;
3037 playlist->rdiff (cmds);
3038 _session->add_commands (cmds);
3040 /* pick up changes to the playlist itself (adds/removes)
3043 _session->add_command(new StatefulDiffCommand (playlist));
3052 // selection->set (new_selection);
3054 commit_reversible_command ();
3058 struct PlaylistState {
3059 boost::shared_ptr<Playlist> playlist;
3063 /** Take tracks from get_tracks_for_range_action and cut any regions
3064 * on those tracks so that the tracks are empty over the time
3068 Editor::separate_region_from_selection ()
3070 /* preferentially use *all* ranges in the time selection if we're in range mode
3071 to allow discontiguous operation, since get_edit_op_range() currently
3072 returns a single range.
3075 if (!selection->time.empty()) {
3077 separate_regions_between (selection->time);
3084 if (get_edit_op_range (start, end)) {
3086 AudioRange ar (start, end, 1);
3090 separate_regions_between (ts);
3096 Editor::separate_region_from_punch ()
3098 Location* loc = _session->locations()->auto_punch_location();
3100 separate_regions_using_location (*loc);
3105 Editor::separate_region_from_loop ()
3107 Location* loc = _session->locations()->auto_loop_location();
3109 separate_regions_using_location (*loc);
3114 Editor::separate_regions_using_location (Location& loc)
3116 if (loc.is_mark()) {
3120 AudioRange ar (loc.start(), loc.end(), 1);
3125 separate_regions_between (ts);
3128 /** Separate regions under the selected region */
3130 Editor::separate_under_selected_regions ()
3132 vector<PlaylistState> playlists;
3136 rs = get_regions_from_selection_and_entered();
3138 if (!_session || rs.empty()) {
3142 begin_reversible_command (_("separate region under"));
3144 list<boost::shared_ptr<Region> > regions_to_remove;
3146 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3147 // we can't just remove the region(s) in this loop because
3148 // this removes them from the RegionSelection, and they thus
3149 // disappear from underneath the iterator, and the ++i above
3150 // SEGVs in a puzzling fashion.
3152 // so, first iterate over the regions to be removed from rs and
3153 // add them to the regions_to_remove list, and then
3154 // iterate over the list to actually remove them.
3156 regions_to_remove.push_back ((*i)->region());
3159 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3161 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3164 // is this check necessary?
3168 vector<PlaylistState>::iterator i;
3170 //only take state if this is a new playlist.
3171 for (i = playlists.begin(); i != playlists.end(); ++i) {
3172 if ((*i).playlist == playlist) {
3177 if (i == playlists.end()) {
3179 PlaylistState before;
3180 before.playlist = playlist;
3181 before.before = &playlist->get_state();
3183 playlist->freeze ();
3184 playlists.push_back(before);
3187 //Partition on the region bounds
3188 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3190 //Re-add region that was just removed due to the partition operation
3191 playlist->add_region( (*rl), (*rl)->first_frame() );
3194 vector<PlaylistState>::iterator pl;
3196 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3197 (*pl).playlist->thaw ();
3198 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3201 commit_reversible_command ();
3205 Editor::crop_region_to_selection ()
3207 if (!selection->time.empty()) {
3209 crop_region_to (selection->time.start(), selection->time.end_frame());
3216 if (get_edit_op_range (start, end)) {
3217 crop_region_to (start, end);
3224 Editor::crop_region_to (framepos_t start, framepos_t end)
3226 vector<boost::shared_ptr<Playlist> > playlists;
3227 boost::shared_ptr<Playlist> playlist;
3230 if (selection->tracks.empty()) {
3231 ts = track_views.filter_to_unique_playlists();
3233 ts = selection->tracks.filter_to_unique_playlists ();
3236 sort_track_selection (ts);
3238 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3240 RouteTimeAxisView* rtv;
3242 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3244 boost::shared_ptr<Track> t = rtv->track();
3246 if (t != 0 && ! t->destructive()) {
3248 if ((playlist = rtv->playlist()) != 0) {
3249 playlists.push_back (playlist);
3255 if (playlists.empty()) {
3259 framepos_t the_start;
3262 bool in_command = false;
3264 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3266 /* Only the top regions at start and end have to be cropped */
3267 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3268 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3270 vector<boost::shared_ptr<Region>> regions;
3272 if (region_at_start != 0) {
3273 regions.push_back (region_at_start);
3275 if (region_at_end != 0) {
3276 regions.push_back (region_at_end);
3279 /* now adjust lengths */
3280 for (vector<boost::shared_ptr<Region>>::iterator i = regions.begin(); i != regions.end(); ++i) {
3282 the_start = max (start, (framepos_t) (*i)->position());
3283 if (max_framepos - the_start < (*i)->length()) {
3284 the_end = the_start + (*i)->length() - 1;
3286 the_end = max_framepos;
3288 the_end = min (end, the_end);
3289 cnt = the_end - the_start + 1;
3292 begin_reversible_command (_("trim to selection"));
3295 (*i)->clear_changes ();
3296 (*i)->trim_to (the_start, cnt);
3297 _session->add_command (new StatefulDiffCommand (*i));
3302 commit_reversible_command ();
3307 Editor::region_fill_track ()
3309 boost::shared_ptr<Playlist> playlist;
3310 RegionSelection regions = get_regions_from_selection_and_entered ();
3311 RegionSelection foo;
3313 framepos_t const end = _session->current_end_frame ();
3315 if (regions.empty () || regions.end_frame () + 1 >= end) {
3319 framepos_t const start_frame = regions.start ();
3320 framepos_t const end_frame = regions.end_frame ();
3321 framecnt_t const gap = end_frame - start_frame + 1;
3323 begin_reversible_command (Operations::region_fill);
3325 selection->clear_regions ();
3327 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3329 boost::shared_ptr<Region> r ((*i)->region());
3331 TimeAxisView& tv = (*i)->get_time_axis_view();
3332 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3333 latest_regionviews.clear ();
3334 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3336 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3337 playlist = (*i)->region()->playlist();
3338 playlist->clear_changes ();
3339 playlist->duplicate_until (r, position, gap, end);
3340 _session->add_command(new StatefulDiffCommand (playlist));
3344 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3348 selection->set (foo);
3351 commit_reversible_command ();
3355 Editor::region_fill_selection ()
3357 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3361 if (selection->time.empty()) {
3365 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3370 framepos_t start = selection->time[clicked_selection].start;
3371 framepos_t end = selection->time[clicked_selection].end;
3373 boost::shared_ptr<Playlist> playlist;
3375 if (selection->tracks.empty()) {
3379 framepos_t selection_length = end - start;
3380 float times = (float)selection_length / region->length();
3381 bool in_command = false;
3383 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3384 RegionSelection foo;
3386 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3388 if ((playlist = (*i)->playlist()) == 0) {
3393 begin_reversible_command (Operations::fill_selection);
3396 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3397 latest_regionviews.clear ();
3398 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3400 playlist->clear_changes ();
3401 playlist->add_region (RegionFactory::create (region, true), start, times);
3402 _session->add_command (new StatefulDiffCommand (playlist));
3404 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3409 selection->set (foo);
3411 commit_reversible_command ();
3416 Editor::set_region_sync_position ()
3418 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3422 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3424 bool in_command = false;
3426 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3428 if (!(*r)->region()->covers (where)) {
3432 boost::shared_ptr<Region> region ((*r)->region());
3435 begin_reversible_command (_("set sync point"));
3439 region->clear_changes ();
3440 region->set_sync_position (where);
3441 _session->add_command(new StatefulDiffCommand (region));
3445 commit_reversible_command ();
3449 /** Remove the sync positions of the selection */
3451 Editor::remove_region_sync ()
3453 RegionSelection rs = get_regions_from_selection_and_entered ();
3459 begin_reversible_command (_("remove region sync"));
3461 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3463 (*i)->region()->clear_changes ();
3464 (*i)->region()->clear_sync_position ();
3465 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3468 commit_reversible_command ();
3472 Editor::naturalize_region ()
3474 RegionSelection rs = get_regions_from_selection_and_entered ();
3480 if (rs.size() > 1) {
3481 begin_reversible_command (_("move regions to original position"));
3483 begin_reversible_command (_("move region to original position"));
3486 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3487 (*i)->region()->clear_changes ();
3488 (*i)->region()->move_to_natural_position ();
3489 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3492 commit_reversible_command ();
3496 Editor::align_regions (RegionPoint what)
3498 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3504 begin_reversible_command (_("align selection"));
3506 framepos_t const position = get_preferred_edit_position ();
3508 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3509 align_region_internal ((*i)->region(), what, position);
3512 commit_reversible_command ();
3515 struct RegionSortByTime {
3516 bool operator() (const RegionView* a, const RegionView* b) {
3517 return a->region()->position() < b->region()->position();
3522 Editor::align_regions_relative (RegionPoint point)
3524 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3530 framepos_t const position = get_preferred_edit_position ();
3532 framepos_t distance = 0;
3536 list<RegionView*> sorted;
3537 rs.by_position (sorted);
3539 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3544 if (position > r->position()) {
3545 distance = position - r->position();
3547 distance = r->position() - position;
3553 if (position > r->last_frame()) {
3554 distance = position - r->last_frame();
3555 pos = r->position() + distance;
3557 distance = r->last_frame() - position;
3558 pos = r->position() - distance;
3564 pos = r->adjust_to_sync (position);
3565 if (pos > r->position()) {
3566 distance = pos - r->position();
3568 distance = r->position() - pos;
3574 if (pos == r->position()) {
3578 begin_reversible_command (_("align selection (relative)"));
3580 /* move first one specially */
3582 r->clear_changes ();
3583 r->set_position (pos);
3584 _session->add_command(new StatefulDiffCommand (r));
3586 /* move rest by the same amount */
3590 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3592 boost::shared_ptr<Region> region ((*i)->region());
3594 region->clear_changes ();
3597 region->set_position (region->position() + distance);
3599 region->set_position (region->position() - distance);
3602 _session->add_command(new StatefulDiffCommand (region));
3606 commit_reversible_command ();
3610 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3612 begin_reversible_command (_("align region"));
3613 align_region_internal (region, point, position);
3614 commit_reversible_command ();
3618 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3620 region->clear_changes ();
3624 region->set_position (region->adjust_to_sync (position));
3628 if (position > region->length()) {
3629 region->set_position (position - region->length());
3634 region->set_position (position);
3638 _session->add_command(new StatefulDiffCommand (region));
3642 Editor::trim_region_front ()
3648 Editor::trim_region_back ()
3650 trim_region (false);
3654 Editor::trim_region (bool front)
3656 framepos_t where = get_preferred_edit_position();
3657 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3663 begin_reversible_command (front ? _("trim front") : _("trim back"));
3665 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3666 if (!(*i)->region()->locked()) {
3668 (*i)->region()->clear_changes ();
3671 (*i)->region()->trim_front (where);
3672 maybe_locate_with_edit_preroll ( where );
3674 (*i)->region()->trim_end (where);
3675 maybe_locate_with_edit_preroll ( where );
3678 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3682 commit_reversible_command ();
3685 /** Trim the end of the selected regions to the position of the edit cursor */
3687 Editor::trim_region_to_loop ()
3689 Location* loc = _session->locations()->auto_loop_location();
3693 trim_region_to_location (*loc, _("trim to loop"));
3697 Editor::trim_region_to_punch ()
3699 Location* loc = _session->locations()->auto_punch_location();
3703 trim_region_to_location (*loc, _("trim to punch"));
3707 Editor::trim_region_to_location (const Location& loc, const char* str)
3709 RegionSelection rs = get_regions_from_selection_and_entered ();
3710 bool in_command = false;
3712 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3713 RegionView* rv = (*x);
3715 /* require region to span proposed trim */
3716 switch (rv->region()->coverage (loc.start(), loc.end())) {
3717 case Evoral::OverlapInternal:
3723 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3732 if (tav->track() != 0) {
3733 speed = tav->track()->speed();
3736 start = session_frame_to_track_frame (loc.start(), speed);
3737 end = session_frame_to_track_frame (loc.end(), speed);
3739 rv->region()->clear_changes ();
3740 rv->region()->trim_to (start, (end - start));
3743 begin_reversible_command (str);
3746 _session->add_command(new StatefulDiffCommand (rv->region()));
3750 commit_reversible_command ();
3755 Editor::trim_region_to_previous_region_end ()
3757 return trim_to_region(false);
3761 Editor::trim_region_to_next_region_start ()
3763 return trim_to_region(true);
3767 Editor::trim_to_region(bool forward)
3769 RegionSelection rs = get_regions_from_selection_and_entered ();
3770 bool in_command = false;
3772 boost::shared_ptr<Region> next_region;
3774 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3776 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3782 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3790 if (atav->track() != 0) {
3791 speed = atav->track()->speed();
3795 boost::shared_ptr<Region> region = arv->region();
3796 boost::shared_ptr<Playlist> playlist (region->playlist());
3798 region->clear_changes ();
3802 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3808 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3809 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3813 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3819 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3821 arv->region_changed (ARDOUR::bounds_change);
3825 begin_reversible_command (_("trim to region"));
3828 _session->add_command(new StatefulDiffCommand (region));
3832 commit_reversible_command ();
3837 Editor::unfreeze_route ()
3839 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3843 clicked_routeview->track()->unfreeze ();
3847 Editor::_freeze_thread (void* arg)
3849 return static_cast<Editor*>(arg)->freeze_thread ();
3853 Editor::freeze_thread ()
3855 /* create event pool because we may need to talk to the session */
3856 SessionEvent::create_per_thread_pool ("freeze events", 64);
3857 /* create per-thread buffers for process() tree to use */
3858 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3859 current_interthread_info->done = true;
3864 Editor::freeze_route ()
3870 /* stop transport before we start. this is important */
3872 _session->request_transport_speed (0.0);
3874 /* wait for just a little while, because the above call is asynchronous */
3876 Glib::usleep (250000);
3878 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3882 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3884 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3885 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3887 d.set_title (_("Cannot freeze"));
3892 if (clicked_routeview->track()->has_external_redirects()) {
3893 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"
3894 "Freezing will only process the signal as far as the first send/insert/return."),
3895 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3897 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3898 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3899 d.set_title (_("Freeze Limits"));
3901 int response = d.run ();
3904 case Gtk::RESPONSE_CANCEL:
3911 InterThreadInfo itt;
3912 current_interthread_info = &itt;
3914 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3916 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3918 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3920 while (!itt.done && !itt.cancel) {
3921 gtk_main_iteration ();
3924 current_interthread_info = 0;
3928 Editor::bounce_range_selection (bool replace, bool enable_processing)
3930 if (selection->time.empty()) {
3934 TrackSelection views = selection->tracks;
3936 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3938 if (enable_processing) {
3940 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3942 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3944 _("You can't perform this operation because the processing of the signal "
3945 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3946 "You can do this without processing, which is a different operation.")
3948 d.set_title (_("Cannot bounce"));
3955 framepos_t start = selection->time[clicked_selection].start;
3956 framepos_t end = selection->time[clicked_selection].end;
3957 framepos_t cnt = end - start + 1;
3958 bool in_command = false;
3960 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3962 RouteTimeAxisView* rtv;
3964 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3968 boost::shared_ptr<Playlist> playlist;
3970 if ((playlist = rtv->playlist()) == 0) {
3974 InterThreadInfo itt;
3976 playlist->clear_changes ();
3977 playlist->clear_owned_changes ();
3979 boost::shared_ptr<Region> r;
3981 if (enable_processing) {
3982 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3984 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3992 list<AudioRange> ranges;
3993 ranges.push_back (AudioRange (start, start+cnt, 0));
3994 playlist->cut (ranges); // discard result
3995 playlist->add_region (r, start);
3999 begin_reversible_command (_("bounce range"));
4002 vector<Command*> cmds;
4003 playlist->rdiff (cmds);
4004 _session->add_commands (cmds);
4006 _session->add_command (new StatefulDiffCommand (playlist));
4010 commit_reversible_command ();
4014 /** Delete selected regions, automation points or a time range */
4018 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4019 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4020 bool deleted = false;
4021 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4022 deleted = current_mixer_strip->delete_processors ();
4028 /** Cut selected regions, automation points or a time range */
4035 /** Copy selected regions, automation points or a time range */
4043 /** @return true if a Cut, Copy or Clear is possible */
4045 Editor::can_cut_copy () const
4047 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4054 /** Cut, copy or clear selected regions, automation points or a time range.
4055 * @param op Operation (Delete, Cut, Copy or Clear)
4058 Editor::cut_copy (CutCopyOp op)
4060 /* only cancel selection if cut/copy is successful.*/
4066 opname = _("delete");
4075 opname = _("clear");
4079 /* if we're deleting something, and the mouse is still pressed,
4080 the thing we started a drag for will be gone when we release
4081 the mouse button(s). avoid this. see part 2 at the end of
4085 if (op == Delete || op == Cut || op == Clear) {
4086 if (_drags->active ()) {
4091 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4092 cut_buffer->clear ();
4094 if (entered_marker) {
4096 /* cut/delete op while pointing at a marker */
4099 Location* loc = find_location_from_marker (entered_marker, ignored);
4101 if (_session && loc) {
4102 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4109 switch (mouse_mode) {
4112 begin_reversible_command (opname + ' ' + X_("MIDI"));
4114 commit_reversible_command ();
4120 bool did_edit = false;
4122 if (!selection->regions.empty() || !selection->points.empty()) {
4123 begin_reversible_command (opname + ' ' + _("objects"));
4126 if (!selection->regions.empty()) {
4127 cut_copy_regions (op, selection->regions);
4129 if (op == Cut || op == Delete) {
4130 selection->clear_regions ();
4134 if (!selection->points.empty()) {
4135 cut_copy_points (op);
4137 if (op == Cut || op == Delete) {
4138 selection->clear_points ();
4141 } else if (selection->time.empty()) {
4142 framepos_t start, end;
4143 /* no time selection, see if we can get an edit range
4146 if (get_edit_op_range (start, end)) {
4147 selection->set (start, end);
4149 } else if (!selection->time.empty()) {
4150 begin_reversible_command (opname + ' ' + _("range"));
4153 cut_copy_ranges (op);
4155 if (op == Cut || op == Delete) {
4156 selection->clear_time ();
4161 /* reset repeated paste state */
4164 commit_reversible_command ();
4167 if (op == Delete || op == Cut || op == Clear) {
4172 struct AutomationRecord {
4173 AutomationRecord () : state (0) , line(NULL) {}
4174 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4176 XMLNode* state; ///< state before any operation
4177 const AutomationLine* line; ///< line this came from
4178 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4181 /** Cut, copy or clear selected automation points.
4182 * @param op Operation (Cut, Copy or Clear)
4185 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4187 if (selection->points.empty ()) {
4191 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4192 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4194 /* Keep a record of the AutomationLists that we end up using in this operation */
4195 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4198 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4199 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4200 const AutomationLine& line = (*i)->line();
4201 const boost::shared_ptr<AutomationList> al = line.the_list();
4202 if (lists.find (al) == lists.end ()) {
4203 /* We haven't seen this list yet, so make a record for it. This includes
4204 taking a copy of its current state, in case this is needed for undo later.
4206 lists[al] = AutomationRecord (&al->get_state (), &line);
4210 if (op == Cut || op == Copy) {
4211 /* This operation will involve putting things in the cut buffer, so create an empty
4212 ControlList for each of our source lists to put the cut buffer data in.
4214 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4215 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4218 /* Add all selected points to the relevant copy ControlLists */
4219 framepos_t start = std::numeric_limits<framepos_t>::max();
4220 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4221 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4222 AutomationList::const_iterator j = (*i)->model();
4224 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4226 /* Update earliest MIDI start time in beats */
4227 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4229 /* Update earliest session start time in frames */
4230 start = std::min(start, (*i)->line().session_position(j));
4234 /* Snap start time backwards, so copy/paste is snap aligned. */
4236 if (earliest == Evoral::Beats::max()) {
4237 earliest = Evoral::Beats(); // Weird... don't offset
4239 earliest.round_down_to_beat();
4241 if (start == std::numeric_limits<double>::max()) {
4242 start = 0; // Weird... don't offset
4244 snap_to(start, RoundDownMaybe);
4247 const double line_offset = midi ? earliest.to_double() : start;
4248 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4249 /* Correct this copy list so that it is relative to the earliest
4250 start time, so relative ordering between points is preserved
4251 when copying from several lists and the paste starts at the
4252 earliest copied piece of data. */
4253 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4254 (*j)->when -= line_offset;
4257 /* And add it to the cut buffer */
4258 cut_buffer->add (i->second.copy);
4262 if (op == Delete || op == Cut) {
4263 /* This operation needs to remove things from the main AutomationList, so do that now */
4265 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4266 i->first->freeze ();
4269 /* Remove each selected point from its AutomationList */
4270 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4271 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4272 al->erase ((*i)->model ());
4275 /* Thaw the lists and add undo records for them */
4276 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4277 boost::shared_ptr<AutomationList> al = i->first;
4279 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4284 /** Cut, copy or clear selected automation points.
4285 * @param op Operation (Cut, Copy or Clear)
4288 Editor::cut_copy_midi (CutCopyOp op)
4290 Evoral::Beats earliest = Evoral::Beats::max();
4291 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4292 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4294 if (!mrv->selection().empty()) {
4295 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4297 mrv->cut_copy_clear (op);
4299 /* XXX: not ideal, as there may be more than one track involved in the selection */
4300 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4304 if (!selection->points.empty()) {
4305 cut_copy_points (op, earliest, true);
4306 if (op == Cut || op == Delete) {
4307 selection->clear_points ();
4312 struct lt_playlist {
4313 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4314 return a.playlist < b.playlist;
4318 struct PlaylistMapping {
4320 boost::shared_ptr<Playlist> pl;
4322 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4325 /** Remove `clicked_regionview' */
4327 Editor::remove_clicked_region ()
4329 if (clicked_routeview == 0 || clicked_regionview == 0) {
4333 begin_reversible_command (_("remove region"));
4335 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4337 playlist->clear_changes ();
4338 playlist->clear_owned_changes ();
4339 playlist->remove_region (clicked_regionview->region());
4340 if (Config->get_edit_mode() == Ripple)
4341 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4343 /* We might have removed regions, which alters other regions' layering_index,
4344 so we need to do a recursive diff here.
4346 vector<Command*> cmds;
4347 playlist->rdiff (cmds);
4348 _session->add_commands (cmds);
4350 _session->add_command(new StatefulDiffCommand (playlist));
4351 commit_reversible_command ();
4355 /** Remove the selected regions */
4357 Editor::remove_selected_regions ()
4359 RegionSelection rs = get_regions_from_selection_and_entered ();
4361 if (!_session || rs.empty()) {
4365 list<boost::shared_ptr<Region> > regions_to_remove;
4367 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4368 // we can't just remove the region(s) in this loop because
4369 // this removes them from the RegionSelection, and they thus
4370 // disappear from underneath the iterator, and the ++i above
4371 // SEGVs in a puzzling fashion.
4373 // so, first iterate over the regions to be removed from rs and
4374 // add them to the regions_to_remove list, and then
4375 // iterate over the list to actually remove them.
4377 regions_to_remove.push_back ((*i)->region());
4380 vector<boost::shared_ptr<Playlist> > playlists;
4382 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4384 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4387 // is this check necessary?
4391 /* get_regions_from_selection_and_entered() guarantees that
4392 the playlists involved are unique, so there is no need
4396 playlists.push_back (playlist);
4398 playlist->clear_changes ();
4399 playlist->clear_owned_changes ();
4400 playlist->freeze ();
4401 playlist->remove_region (*rl);
4402 if (Config->get_edit_mode() == Ripple)
4403 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4407 vector<boost::shared_ptr<Playlist> >::iterator pl;
4408 bool in_command = false;
4410 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4413 /* We might have removed regions, which alters other regions' layering_index,
4414 so we need to do a recursive diff here.
4418 begin_reversible_command (_("remove region"));
4421 vector<Command*> cmds;
4422 (*pl)->rdiff (cmds);
4423 _session->add_commands (cmds);
4425 _session->add_command(new StatefulDiffCommand (*pl));
4429 commit_reversible_command ();
4433 /** Cut, copy or clear selected regions.
4434 * @param op Operation (Cut, Copy or Clear)
4437 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4439 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4440 a map when we want ordered access to both elements. i think.
4443 vector<PlaylistMapping> pmap;
4445 framepos_t first_position = max_framepos;
4447 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4448 FreezeList freezelist;
4450 /* get ordering correct before we cut/copy */
4452 rs.sort_by_position_and_track ();
4454 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4456 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4458 if (op == Cut || op == Clear || op == Delete) {
4459 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4462 FreezeList::iterator fl;
4464 // only take state if this is a new playlist.
4465 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4471 if (fl == freezelist.end()) {
4472 pl->clear_changes();
4473 pl->clear_owned_changes ();
4475 freezelist.insert (pl);
4480 TimeAxisView* tv = &(*x)->get_time_axis_view();
4481 vector<PlaylistMapping>::iterator z;
4483 for (z = pmap.begin(); z != pmap.end(); ++z) {
4484 if ((*z).tv == tv) {
4489 if (z == pmap.end()) {
4490 pmap.push_back (PlaylistMapping (tv));
4494 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4496 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4499 /* region not yet associated with a playlist (e.g. unfinished
4506 TimeAxisView& tv = (*x)->get_time_axis_view();
4507 boost::shared_ptr<Playlist> npl;
4508 RegionSelection::iterator tmp;
4515 vector<PlaylistMapping>::iterator z;
4517 for (z = pmap.begin(); z != pmap.end(); ++z) {
4518 if ((*z).tv == &tv) {
4523 assert (z != pmap.end());
4526 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4534 boost::shared_ptr<Region> r = (*x)->region();
4535 boost::shared_ptr<Region> _xx;
4541 pl->remove_region (r);
4542 if (Config->get_edit_mode() == Ripple)
4543 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4547 _xx = RegionFactory::create (r);
4548 npl->add_region (_xx, r->position() - first_position);
4549 pl->remove_region (r);
4550 if (Config->get_edit_mode() == Ripple)
4551 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4555 /* copy region before adding, so we're not putting same object into two different playlists */
4556 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4560 pl->remove_region (r);
4561 if (Config->get_edit_mode() == Ripple)
4562 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4571 list<boost::shared_ptr<Playlist> > foo;
4573 /* the pmap is in the same order as the tracks in which selected regions occured */
4575 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4578 foo.push_back ((*i).pl);
4583 cut_buffer->set (foo);
4587 _last_cut_copy_source_track = 0;
4589 _last_cut_copy_source_track = pmap.front().tv;
4593 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4596 /* We might have removed regions, which alters other regions' layering_index,
4597 so we need to do a recursive diff here.
4599 vector<Command*> cmds;
4600 (*pl)->rdiff (cmds);
4601 _session->add_commands (cmds);
4603 _session->add_command (new StatefulDiffCommand (*pl));
4608 Editor::cut_copy_ranges (CutCopyOp op)
4610 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4612 /* Sort the track selection now, so that it if is used, the playlists
4613 selected by the calls below to cut_copy_clear are in the order that
4614 their tracks appear in the editor. This makes things like paste
4615 of ranges work properly.
4618 sort_track_selection (ts);
4621 if (!entered_track) {
4624 ts.push_back (entered_track);
4627 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4628 (*i)->cut_copy_clear (*selection, op);
4633 Editor::paste (float times, bool from_context)
4635 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4637 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4641 Editor::mouse_paste ()
4646 if (!mouse_frame (where, ignored)) {
4651 paste_internal (where, 1);
4655 Editor::paste_internal (framepos_t position, float times)
4657 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4659 if (cut_buffer->empty(internal_editing())) {
4663 if (position == max_framepos) {
4664 position = get_preferred_edit_position();
4665 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4668 if (position == last_paste_pos) {
4669 /* repeated paste in the same position */
4672 /* paste in new location, reset repeated paste state */
4674 last_paste_pos = position;
4677 /* get everything in the correct order */
4680 if (!selection->tracks.empty()) {
4681 /* If there is a track selection, paste into exactly those tracks and
4682 only those tracks. This allows the user to be explicit and override
4683 the below "do the reasonable thing" logic. */
4684 ts = selection->tracks.filter_to_unique_playlists ();
4685 sort_track_selection (ts);
4687 /* Figure out which track to base the paste at. */
4688 TimeAxisView* base_track = NULL;
4689 if (_edit_point == Editing::EditAtMouse && entered_track) {
4690 /* With the mouse edit point, paste onto the track under the mouse. */
4691 base_track = entered_track;
4692 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4693 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4694 base_track = &entered_regionview->get_time_axis_view();
4695 } else if (_last_cut_copy_source_track) {
4696 /* Paste to the track that the cut/copy came from (see mantis #333). */
4697 base_track = _last_cut_copy_source_track;
4699 /* This is "impossible" since we've copied... well, do nothing. */
4703 /* Walk up to parent if necessary, so base track is a route. */
4704 while (base_track->get_parent()) {
4705 base_track = base_track->get_parent();
4708 /* Add base track and all tracks below it. The paste logic will select
4709 the appropriate object types from the cut buffer in relative order. */
4710 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4711 if ((*i)->order() >= base_track->order()) {
4716 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4717 sort_track_selection (ts);
4719 /* Add automation children of each track in order, for pasting several lines. */
4720 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4721 /* Add any automation children for pasting several lines */
4722 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4727 typedef RouteTimeAxisView::AutomationTracks ATracks;
4728 const ATracks& atracks = rtv->automation_tracks();
4729 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4730 i = ts.insert(i, a->second.get());
4735 /* We now have a list of trackviews starting at base_track, including
4736 automation children, in the order shown in the editor, e.g. R1,
4737 R1.A1, R1.A2, R2, R2.A1, ... */
4740 begin_reversible_command (Operations::paste);
4742 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4743 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4744 /* Only one line copied, and one automation track selected. Do a
4745 "greedy" paste from one automation type to another. */
4747 PasteContext ctx(paste_count, times, ItemCounts(), true);
4748 ts.front()->paste (position, *cut_buffer, ctx);
4752 /* Paste into tracks */
4754 PasteContext ctx(paste_count, times, ItemCounts(), false);
4755 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4756 (*i)->paste (position, *cut_buffer, ctx);
4760 commit_reversible_command ();
4764 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4766 if (regions.empty ()) {
4770 boost::shared_ptr<Playlist> playlist;
4771 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4772 RegionSelection foo;
4774 framepos_t const start_frame = regions.start ();
4775 framepos_t const end_frame = regions.end_frame ();
4776 framecnt_t const gap = end_frame - start_frame + 1;
4778 begin_reversible_command (Operations::duplicate_region);
4780 selection->clear_regions ();
4782 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4784 boost::shared_ptr<Region> r ((*i)->region());
4786 TimeAxisView& tv = (*i)->get_time_axis_view();
4787 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4788 latest_regionviews.clear ();
4789 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4791 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4792 playlist = (*i)->region()->playlist();
4793 playlist->clear_changes ();
4794 playlist->duplicate (r, position, gap, times);
4795 _session->add_command(new StatefulDiffCommand (playlist));
4799 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4803 selection->set (foo);
4806 commit_reversible_command ();
4810 Editor::duplicate_selection (float times)
4812 if (selection->time.empty() || selection->tracks.empty()) {
4816 boost::shared_ptr<Playlist> playlist;
4817 vector<boost::shared_ptr<Region> > new_regions;
4818 vector<boost::shared_ptr<Region> >::iterator ri;
4820 create_region_from_selection (new_regions);
4822 if (new_regions.empty()) {
4826 ri = new_regions.begin();
4828 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4829 bool in_command = false;
4831 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4832 if ((playlist = (*i)->playlist()) == 0) {
4835 playlist->clear_changes ();
4837 if (clicked_selection) {
4838 end = selection->time[clicked_selection].end;
4840 end = selection->time.end_frame();
4842 playlist->duplicate (*ri, end + 1, times);
4845 begin_reversible_command (_("duplicate selection"));
4848 _session->add_command (new StatefulDiffCommand (playlist));
4851 if (ri == new_regions.end()) {
4857 commit_reversible_command ();
4861 /** Reset all selected points to the relevant default value */
4863 Editor::reset_point_selection ()
4865 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4866 ARDOUR::AutomationList::iterator j = (*i)->model ();
4867 (*j)->value = (*i)->line().the_list()->default_value ();
4872 Editor::center_playhead ()
4874 float const page = _visible_canvas_width * samples_per_pixel;
4875 center_screen_internal (playhead_cursor->current_frame (), page);
4879 Editor::center_edit_point ()
4881 float const page = _visible_canvas_width * samples_per_pixel;
4882 center_screen_internal (get_preferred_edit_position(), page);
4885 /** Caller must begin and commit a reversible command */
4887 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4889 playlist->clear_changes ();
4891 _session->add_command (new StatefulDiffCommand (playlist));
4895 Editor::nudge_track (bool use_edit, bool forwards)
4897 boost::shared_ptr<Playlist> playlist;
4898 framepos_t distance;
4899 framepos_t next_distance;
4903 start = get_preferred_edit_position();
4908 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4912 if (selection->tracks.empty()) {
4916 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4917 bool in_command = false;
4919 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4921 if ((playlist = (*i)->playlist()) == 0) {
4925 playlist->clear_changes ();
4926 playlist->clear_owned_changes ();
4928 playlist->nudge_after (start, distance, forwards);
4931 begin_reversible_command (_("nudge track"));
4934 vector<Command*> cmds;
4936 playlist->rdiff (cmds);
4937 _session->add_commands (cmds);
4939 _session->add_command (new StatefulDiffCommand (playlist));
4943 commit_reversible_command ();
4948 Editor::remove_last_capture ()
4950 vector<string> choices;
4957 if (Config->get_verify_remove_last_capture()) {
4958 prompt = _("Do you really want to destroy the last capture?"
4959 "\n(This is destructive and cannot be undone)");
4961 choices.push_back (_("No, do nothing."));
4962 choices.push_back (_("Yes, destroy it."));
4964 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4966 if (prompter.run () == 1) {
4967 _session->remove_last_capture ();
4968 _regions->redisplay ();
4972 _session->remove_last_capture();
4973 _regions->redisplay ();
4978 Editor::normalize_region ()
4984 RegionSelection rs = get_regions_from_selection_and_entered ();
4990 NormalizeDialog dialog (rs.size() > 1);
4992 if (dialog.run () == RESPONSE_CANCEL) {
4996 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4999 /* XXX: should really only count audio regions here */
5000 int const regions = rs.size ();
5002 /* Make a list of the selected audio regions' maximum amplitudes, and also
5003 obtain the maximum amplitude of them all.
5005 list<double> max_amps;
5007 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5008 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5010 dialog.descend (1.0 / regions);
5011 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5014 /* the user cancelled the operation */
5018 max_amps.push_back (a);
5019 max_amp = max (max_amp, a);
5024 list<double>::const_iterator a = max_amps.begin ();
5025 bool in_command = false;
5027 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5028 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5033 arv->region()->clear_changes ();
5035 double const amp = dialog.normalize_individually() ? *a : max_amp;
5037 arv->audio_region()->normalize (amp, dialog.target ());
5040 begin_reversible_command (_("normalize"));
5043 _session->add_command (new StatefulDiffCommand (arv->region()));
5049 commit_reversible_command ();
5055 Editor::reset_region_scale_amplitude ()
5061 RegionSelection rs = get_regions_from_selection_and_entered ();
5067 bool in_command = false;
5069 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5070 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5073 arv->region()->clear_changes ();
5074 arv->audio_region()->set_scale_amplitude (1.0f);
5077 begin_reversible_command ("reset gain");
5080 _session->add_command (new StatefulDiffCommand (arv->region()));
5084 commit_reversible_command ();
5089 Editor::adjust_region_gain (bool up)
5091 RegionSelection rs = get_regions_from_selection_and_entered ();
5093 if (!_session || rs.empty()) {
5097 bool in_command = false;
5099 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5100 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5105 arv->region()->clear_changes ();
5107 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5115 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5118 begin_reversible_command ("adjust region gain");
5121 _session->add_command (new StatefulDiffCommand (arv->region()));
5125 commit_reversible_command ();
5131 Editor::reverse_region ()
5137 Reverse rev (*_session);
5138 apply_filter (rev, _("reverse regions"));
5142 Editor::strip_region_silence ()
5148 RegionSelection rs = get_regions_from_selection_and_entered ();
5154 std::list<RegionView*> audio_only;
5156 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5157 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5159 audio_only.push_back (arv);
5163 assert (!audio_only.empty());
5165 StripSilenceDialog d (_session, audio_only);
5166 int const r = d.run ();
5170 if (r == Gtk::RESPONSE_OK) {
5171 ARDOUR::AudioIntervalMap silences;
5172 d.silences (silences);
5173 StripSilence s (*_session, silences, d.fade_length());
5174 apply_filter (s, _("strip silence"), &d);
5179 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5181 Evoral::Sequence<Evoral::Beats>::Notes selected;
5182 mrv.selection_as_notelist (selected, true);
5184 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5185 v.push_back (selected);
5187 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5188 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5190 return op (mrv.midi_region()->model(), pos_beats, v);
5194 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5200 bool in_command = false;
5202 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5203 RegionSelection::const_iterator tmp = r;
5206 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5209 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5212 begin_reversible_command (op.name ());
5216 _session->add_command (cmd);
5224 commit_reversible_command ();
5229 Editor::fork_region ()
5231 RegionSelection rs = get_regions_from_selection_and_entered ();
5237 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5238 bool in_command = false;
5242 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5243 RegionSelection::iterator tmp = r;
5246 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5250 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5251 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5252 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5255 begin_reversible_command (_("Fork Region(s)"));
5258 playlist->clear_changes ();
5259 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5260 _session->add_command(new StatefulDiffCommand (playlist));
5262 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5270 commit_reversible_command ();
5275 Editor::quantize_region ()
5278 quantize_regions(get_regions_from_selection_and_entered ());
5283 Editor::quantize_regions (const RegionSelection& rs)
5285 if (rs.n_midi_regions() == 0) {
5289 if (!quantize_dialog) {
5290 quantize_dialog = new QuantizeDialog (*this);
5293 quantize_dialog->present ();
5294 const int r = quantize_dialog->run ();
5295 quantize_dialog->hide ();
5297 if (r == Gtk::RESPONSE_OK) {
5298 Quantize quant (quantize_dialog->snap_start(),
5299 quantize_dialog->snap_end(),
5300 quantize_dialog->start_grid_size(),
5301 quantize_dialog->end_grid_size(),
5302 quantize_dialog->strength(),
5303 quantize_dialog->swing(),
5304 quantize_dialog->threshold());
5306 apply_midi_note_edit_op (quant, rs);
5311 Editor::legatize_region (bool shrink_only)
5314 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5319 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5321 if (rs.n_midi_regions() == 0) {
5325 Legatize legatize(shrink_only);
5326 apply_midi_note_edit_op (legatize, rs);
5330 Editor::transform_region ()
5333 transform_regions(get_regions_from_selection_and_entered ());
5338 Editor::transform_regions (const RegionSelection& rs)
5340 if (rs.n_midi_regions() == 0) {
5347 const int r = td.run();
5350 if (r == Gtk::RESPONSE_OK) {
5351 Transform transform(td.get());
5352 apply_midi_note_edit_op(transform, rs);
5357 Editor::transpose_region ()
5360 transpose_regions(get_regions_from_selection_and_entered ());
5365 Editor::transpose_regions (const RegionSelection& rs)
5367 if (rs.n_midi_regions() == 0) {
5372 int const r = d.run ();
5374 if (r == RESPONSE_ACCEPT) {
5375 Transpose transpose(d.semitones ());
5376 apply_midi_note_edit_op (transpose, rs);
5381 Editor::insert_patch_change (bool from_context)
5383 RegionSelection rs = get_regions_from_selection_and_entered ();
5389 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5391 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5392 there may be more than one, but the PatchChangeDialog can only offer
5393 one set of patch menus.
5395 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5397 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5398 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5400 if (d.run() == RESPONSE_CANCEL) {
5404 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5405 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5407 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5408 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5415 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5417 RegionSelection rs = get_regions_from_selection_and_entered ();
5423 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5424 bool in_command = false;
5429 int const N = rs.size ();
5431 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5432 RegionSelection::iterator tmp = r;
5435 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5437 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5440 progress->descend (1.0 / N);
5443 if (arv->audio_region()->apply (filter, progress) == 0) {
5445 playlist->clear_changes ();
5446 playlist->clear_owned_changes ();
5448 if (filter.results.empty ()) {
5450 /* no regions returned; remove the old one */
5451 playlist->remove_region (arv->region ());
5455 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5457 /* first region replaces the old one */
5458 playlist->replace_region (arv->region(), *res, (*res)->position());
5462 while (res != filter.results.end()) {
5463 playlist->add_region (*res, (*res)->position());
5468 /* We might have removed regions, which alters other regions' layering_index,
5469 so we need to do a recursive diff here.
5473 begin_reversible_command (command);
5476 vector<Command*> cmds;
5477 playlist->rdiff (cmds);
5478 _session->add_commands (cmds);
5480 _session->add_command(new StatefulDiffCommand (playlist));
5484 progress->ascend ();
5493 commit_reversible_command ();
5498 Editor::external_edit_region ()
5504 Editor::reset_region_gain_envelopes ()
5506 RegionSelection rs = get_regions_from_selection_and_entered ();
5508 if (!_session || rs.empty()) {
5512 bool in_command = false;
5514 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5515 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5517 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5518 XMLNode& before (alist->get_state());
5520 arv->audio_region()->set_default_envelope ();
5523 begin_reversible_command (_("reset region gain"));
5526 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5531 commit_reversible_command ();
5536 Editor::set_region_gain_visibility (RegionView* rv)
5538 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5540 arv->update_envelope_visibility();
5545 Editor::set_gain_envelope_visibility ()
5551 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5552 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5554 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5560 Editor::toggle_gain_envelope_active ()
5562 if (_ignore_region_action) {
5566 RegionSelection rs = get_regions_from_selection_and_entered ();
5568 if (!_session || rs.empty()) {
5572 bool in_command = false;
5574 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5575 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5577 arv->region()->clear_changes ();
5578 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5581 begin_reversible_command (_("region gain envelope active"));
5584 _session->add_command (new StatefulDiffCommand (arv->region()));
5589 commit_reversible_command ();
5594 Editor::toggle_region_lock ()
5596 if (_ignore_region_action) {
5600 RegionSelection rs = get_regions_from_selection_and_entered ();
5602 if (!_session || rs.empty()) {
5606 begin_reversible_command (_("toggle region lock"));
5608 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5609 (*i)->region()->clear_changes ();
5610 (*i)->region()->set_locked (!(*i)->region()->locked());
5611 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5614 commit_reversible_command ();
5618 Editor::toggle_region_video_lock ()
5620 if (_ignore_region_action) {
5624 RegionSelection rs = get_regions_from_selection_and_entered ();
5626 if (!_session || rs.empty()) {
5630 begin_reversible_command (_("Toggle Video Lock"));
5632 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5633 (*i)->region()->clear_changes ();
5634 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5635 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5638 commit_reversible_command ();
5642 Editor::toggle_region_lock_style ()
5644 if (_ignore_region_action) {
5648 RegionSelection rs = get_regions_from_selection_and_entered ();
5650 if (!_session || rs.empty()) {
5654 begin_reversible_command (_("region lock style"));
5656 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5657 (*i)->region()->clear_changes ();
5658 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5659 (*i)->region()->set_position_lock_style (ns);
5660 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5663 commit_reversible_command ();
5667 Editor::toggle_opaque_region ()
5669 if (_ignore_region_action) {
5673 RegionSelection rs = get_regions_from_selection_and_entered ();
5675 if (!_session || rs.empty()) {
5679 begin_reversible_command (_("change region opacity"));
5681 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5682 (*i)->region()->clear_changes ();
5683 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5684 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5687 commit_reversible_command ();
5691 Editor::toggle_record_enable ()
5693 bool new_state = false;
5695 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5696 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5699 if (!rtav->is_track())
5703 new_state = !rtav->track()->record_enabled();
5707 rtav->track()->set_record_enabled (new_state, this);
5712 Editor::toggle_solo ()
5714 bool new_state = false;
5716 boost::shared_ptr<RouteList> rl (new RouteList);
5718 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5719 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5726 new_state = !rtav->route()->soloed ();
5730 rl->push_back (rtav->route());
5733 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5737 Editor::toggle_mute ()
5739 bool new_state = false;
5741 boost::shared_ptr<RouteList> rl (new RouteList);
5743 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5744 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5751 new_state = !rtav->route()->muted();
5755 rl->push_back (rtav->route());
5758 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5762 Editor::toggle_solo_isolate ()
5768 Editor::fade_range ()
5770 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5772 begin_reversible_command (_("fade range"));
5774 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5775 (*i)->fade_range (selection->time);
5778 commit_reversible_command ();
5783 Editor::set_fade_length (bool in)
5785 RegionSelection rs = get_regions_from_selection_and_entered ();
5791 /* we need a region to measure the offset from the start */
5793 RegionView* rv = rs.front ();
5795 framepos_t pos = get_preferred_edit_position();
5799 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5800 /* edit point is outside the relevant region */
5805 if (pos <= rv->region()->position()) {
5809 len = pos - rv->region()->position();
5810 cmd = _("set fade in length");
5812 if (pos >= rv->region()->last_frame()) {
5816 len = rv->region()->last_frame() - pos;
5817 cmd = _("set fade out length");
5820 bool in_command = false;
5822 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5823 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5829 boost::shared_ptr<AutomationList> alist;
5831 alist = tmp->audio_region()->fade_in();
5833 alist = tmp->audio_region()->fade_out();
5836 XMLNode &before = alist->get_state();
5839 tmp->audio_region()->set_fade_in_length (len);
5840 tmp->audio_region()->set_fade_in_active (true);
5842 tmp->audio_region()->set_fade_out_length (len);
5843 tmp->audio_region()->set_fade_out_active (true);
5847 begin_reversible_command (cmd);
5850 XMLNode &after = alist->get_state();
5851 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5855 commit_reversible_command ();
5860 Editor::set_fade_in_shape (FadeShape shape)
5862 RegionSelection rs = get_regions_from_selection_and_entered ();
5867 bool in_command = false;
5869 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5870 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5876 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5877 XMLNode &before = alist->get_state();
5879 tmp->audio_region()->set_fade_in_shape (shape);
5882 begin_reversible_command (_("set fade in shape"));
5885 XMLNode &after = alist->get_state();
5886 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5890 commit_reversible_command ();
5895 Editor::set_fade_out_shape (FadeShape shape)
5897 RegionSelection rs = get_regions_from_selection_and_entered ();
5902 bool in_command = false;
5904 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5905 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5911 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5912 XMLNode &before = alist->get_state();
5914 tmp->audio_region()->set_fade_out_shape (shape);
5917 begin_reversible_command (_("set fade out shape"));
5920 XMLNode &after = alist->get_state();
5921 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5925 commit_reversible_command ();
5930 Editor::set_fade_in_active (bool yn)
5932 RegionSelection rs = get_regions_from_selection_and_entered ();
5937 bool in_command = false;
5939 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5940 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5947 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5949 ar->clear_changes ();
5950 ar->set_fade_in_active (yn);
5953 begin_reversible_command (_("set fade in active"));
5956 _session->add_command (new StatefulDiffCommand (ar));
5960 commit_reversible_command ();
5965 Editor::set_fade_out_active (bool yn)
5967 RegionSelection rs = get_regions_from_selection_and_entered ();
5972 bool in_command = false;
5974 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5975 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5981 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5983 ar->clear_changes ();
5984 ar->set_fade_out_active (yn);
5987 begin_reversible_command (_("set fade out active"));
5990 _session->add_command(new StatefulDiffCommand (ar));
5994 commit_reversible_command ();
5999 Editor::toggle_region_fades (int dir)
6001 if (_ignore_region_action) {
6005 boost::shared_ptr<AudioRegion> ar;
6008 RegionSelection rs = get_regions_from_selection_and_entered ();
6014 RegionSelection::iterator i;
6015 for (i = rs.begin(); i != rs.end(); ++i) {
6016 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6018 yn = ar->fade_out_active ();
6020 yn = ar->fade_in_active ();
6026 if (i == rs.end()) {
6030 /* XXX should this undo-able? */
6031 bool in_command = false;
6033 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6034 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6037 ar->clear_changes ();
6039 if (dir == 1 || dir == 0) {
6040 ar->set_fade_in_active (!yn);
6043 if (dir == -1 || dir == 0) {
6044 ar->set_fade_out_active (!yn);
6047 begin_reversible_command (_("toggle fade active"));
6050 _session->add_command(new StatefulDiffCommand (ar));
6054 commit_reversible_command ();
6059 /** Update region fade visibility after its configuration has been changed */
6061 Editor::update_region_fade_visibility ()
6063 bool _fade_visibility = _session->config.get_show_region_fades ();
6065 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6066 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6068 if (_fade_visibility) {
6069 v->audio_view()->show_all_fades ();
6071 v->audio_view()->hide_all_fades ();
6078 Editor::set_edit_point ()
6083 if (!mouse_frame (where, ignored)) {
6089 if (selection->markers.empty()) {
6091 mouse_add_new_marker (where);
6096 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6099 loc->move_to (where);
6105 Editor::set_playhead_cursor ()
6107 if (entered_marker) {
6108 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6113 if (!mouse_frame (where, ignored)) {
6120 _session->request_locate (where, _session->transport_rolling());
6124 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6125 cancel_time_selection();
6130 Editor::split_region ()
6132 if (_drags->active ()) {
6136 //if a range is selected, separate it
6137 if ( !selection->time.empty()) {
6138 separate_regions_between (selection->time);
6142 //if no range was selected, try to find some regions to split
6143 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6145 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6147 framepos_t where = get_preferred_edit_position ();
6153 split_regions_at (where, rs);
6157 struct EditorOrderRouteSorter {
6158 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6159 return a->order_key () < b->order_key ();
6164 Editor::select_next_route()
6166 if (selection->tracks.empty()) {
6167 selection->set (track_views.front());
6171 TimeAxisView* current = selection->tracks.front();
6175 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6176 if (*i == current) {
6178 if (i != track_views.end()) {
6181 current = (*(track_views.begin()));
6182 //selection->set (*(track_views.begin()));
6187 rui = dynamic_cast<RouteUI *>(current);
6188 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6190 selection->set(current);
6192 ensure_time_axis_view_is_visible (*current, false);
6196 Editor::select_prev_route()
6198 if (selection->tracks.empty()) {
6199 selection->set (track_views.front());
6203 TimeAxisView* current = selection->tracks.front();
6207 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6208 if (*i == current) {
6210 if (i != track_views.rend()) {
6213 current = *(track_views.rbegin());
6218 rui = dynamic_cast<RouteUI *>(current);
6219 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6221 selection->set (current);
6223 ensure_time_axis_view_is_visible (*current, false);
6227 Editor::set_loop_from_selection (bool play)
6229 if (_session == 0) {
6233 framepos_t start, end;
6234 if (!get_selection_extents ( start, end))
6237 set_loop_range (start, end, _("set loop range from selection"));
6240 _session->request_play_loop (true, true);
6245 Editor::set_loop_from_region (bool play)
6247 framepos_t start, end;
6248 if (!get_selection_extents ( start, end))
6251 set_loop_range (start, end, _("set loop range from region"));
6254 _session->request_locate (start, true);
6255 _session->request_play_loop (true);
6260 Editor::set_punch_from_selection ()
6262 if (_session == 0) {
6266 framepos_t start, end;
6267 if (!get_selection_extents ( start, end))
6270 set_punch_range (start, end, _("set punch range from selection"));
6274 Editor::set_session_extents_from_selection ()
6276 if (_session == 0) {
6280 framepos_t start, end;
6281 if (!get_selection_extents ( start, end))
6285 if ((loc = _session->locations()->session_range_location()) == 0) {
6286 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6288 XMLNode &before = loc->get_state();
6290 _session->set_session_extents ( start, end );
6292 XMLNode &after = loc->get_state();
6294 begin_reversible_command (_("set session start/end from selection"));
6296 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6298 commit_reversible_command ();
6303 Editor::set_punch_start_from_edit_point ()
6307 framepos_t start = 0;
6308 framepos_t end = max_framepos;
6310 //use the existing punch end, if any
6311 Location* tpl = transport_punch_location();
6316 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6317 start = _session->audible_frame();
6319 start = get_preferred_edit_position();
6322 //snap the selection start/end
6325 //if there's not already a sensible selection endpoint, go "forever"
6326 if ( start > end ) {
6330 set_punch_range (start, end, _("set punch start from EP"));
6336 Editor::set_punch_end_from_edit_point ()
6340 framepos_t start = 0;
6341 framepos_t end = max_framepos;
6343 //use the existing punch start, if any
6344 Location* tpl = transport_punch_location();
6346 start = tpl->start();
6349 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6350 end = _session->audible_frame();
6352 end = get_preferred_edit_position();
6355 //snap the selection start/end
6358 set_punch_range (start, end, _("set punch end from EP"));
6364 Editor::set_loop_start_from_edit_point ()
6368 framepos_t start = 0;
6369 framepos_t end = max_framepos;
6371 //use the existing loop end, if any
6372 Location* tpl = transport_loop_location();
6377 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6378 start = _session->audible_frame();
6380 start = get_preferred_edit_position();
6383 //snap the selection start/end
6386 //if there's not already a sensible selection endpoint, go "forever"
6387 if ( start > end ) {
6391 set_loop_range (start, end, _("set loop start from EP"));
6397 Editor::set_loop_end_from_edit_point ()
6401 framepos_t start = 0;
6402 framepos_t end = max_framepos;
6404 //use the existing loop start, if any
6405 Location* tpl = transport_loop_location();
6407 start = tpl->start();
6410 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6411 end = _session->audible_frame();
6413 end = get_preferred_edit_position();
6416 //snap the selection start/end
6419 set_loop_range (start, end, _("set loop end from EP"));
6424 Editor::set_punch_from_region ()
6426 framepos_t start, end;
6427 if (!get_selection_extents ( start, end))
6430 set_punch_range (start, end, _("set punch range from region"));
6434 Editor::pitch_shift_region ()
6436 RegionSelection rs = get_regions_from_selection_and_entered ();
6438 RegionSelection audio_rs;
6439 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6440 if (dynamic_cast<AudioRegionView*> (*i)) {
6441 audio_rs.push_back (*i);
6445 if (audio_rs.empty()) {
6449 pitch_shift (audio_rs, 1.2);
6453 Editor::set_tempo_from_region ()
6455 RegionSelection rs = get_regions_from_selection_and_entered ();
6457 if (!_session || rs.empty()) {
6461 RegionView* rv = rs.front();
6463 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6467 Editor::use_range_as_bar ()
6469 framepos_t start, end;
6470 if (get_edit_op_range (start, end)) {
6471 define_one_bar (start, end);
6476 Editor::define_one_bar (framepos_t start, framepos_t end)
6478 framepos_t length = end - start;
6480 const Meter& m (_session->tempo_map().meter_at (start));
6482 /* length = 1 bar */
6484 /* now we want frames per beat.
6485 we have frames per bar, and beats per bar, so ...
6488 /* XXXX METER MATH */
6490 double frames_per_beat = length / m.divisions_per_bar();
6492 /* beats per minute = */
6494 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6496 /* now decide whether to:
6498 (a) set global tempo
6499 (b) add a new tempo marker
6503 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6505 bool do_global = false;
6507 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6509 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6510 at the start, or create a new marker
6513 vector<string> options;
6514 options.push_back (_("Cancel"));
6515 options.push_back (_("Add new marker"));
6516 options.push_back (_("Set global tempo"));
6519 _("Define one bar"),
6520 _("Do you want to set the global tempo or add a new tempo marker?"),
6524 c.set_default_response (2);
6540 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6541 if the marker is at the region starter, change it, otherwise add
6546 begin_reversible_command (_("set tempo from region"));
6547 XMLNode& before (_session->tempo_map().get_state());
6550 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6551 } else if (t.frame() == start) {
6552 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6554 Timecode::BBT_Time bbt;
6555 _session->tempo_map().bbt_time (start, bbt);
6556 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6559 XMLNode& after (_session->tempo_map().get_state());
6561 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6562 commit_reversible_command ();
6566 Editor::split_region_at_transients ()
6568 AnalysisFeatureList positions;
6570 RegionSelection rs = get_regions_from_selection_and_entered ();
6572 if (!_session || rs.empty()) {
6576 begin_reversible_command (_("split regions"));
6578 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6580 RegionSelection::iterator tmp;
6585 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6587 if (ar && (ar->get_transients (positions) == 0)) {
6588 split_region_at_points ((*i)->region(), positions, true);
6595 commit_reversible_command ();
6600 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6602 bool use_rhythmic_rodent = false;
6604 boost::shared_ptr<Playlist> pl = r->playlist();
6606 list<boost::shared_ptr<Region> > new_regions;
6612 if (positions.empty()) {
6617 if (positions.size() > 20 && can_ferret) {
6618 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);
6619 MessageDialog msg (msgstr,
6622 Gtk::BUTTONS_OK_CANCEL);
6625 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6626 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6628 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6631 msg.set_title (_("Excessive split?"));
6634 int response = msg.run();
6640 case RESPONSE_APPLY:
6641 use_rhythmic_rodent = true;
6648 if (use_rhythmic_rodent) {
6649 show_rhythm_ferret ();
6653 AnalysisFeatureList::const_iterator x;
6655 pl->clear_changes ();
6656 pl->clear_owned_changes ();
6658 x = positions.begin();
6660 if (x == positions.end()) {
6665 pl->remove_region (r);
6669 while (x != positions.end()) {
6671 /* deal with positons that are out of scope of present region bounds */
6672 if (*x <= 0 || *x > r->length()) {
6677 /* file start = original start + how far we from the initial position ?
6680 framepos_t file_start = r->start() + pos;
6682 /* length = next position - current position
6685 framepos_t len = (*x) - pos;
6687 /* XXX we do we really want to allow even single-sample regions?
6688 shouldn't we have some kind of lower limit on region size?
6697 if (RegionFactory::region_name (new_name, r->name())) {
6701 /* do NOT announce new regions 1 by one, just wait till they are all done */
6705 plist.add (ARDOUR::Properties::start, file_start);
6706 plist.add (ARDOUR::Properties::length, len);
6707 plist.add (ARDOUR::Properties::name, new_name);
6708 plist.add (ARDOUR::Properties::layer, 0);
6710 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6711 /* because we set annouce to false, manually add the new region to the
6714 RegionFactory::map_add (nr);
6716 pl->add_region (nr, r->position() + pos);
6719 new_regions.push_front(nr);
6728 RegionFactory::region_name (new_name, r->name());
6730 /* Add the final region */
6733 plist.add (ARDOUR::Properties::start, r->start() + pos);
6734 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6735 plist.add (ARDOUR::Properties::name, new_name);
6736 plist.add (ARDOUR::Properties::layer, 0);
6738 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6739 /* because we set annouce to false, manually add the new region to the
6742 RegionFactory::map_add (nr);
6743 pl->add_region (nr, r->position() + pos);
6746 new_regions.push_front(nr);
6751 /* We might have removed regions, which alters other regions' layering_index,
6752 so we need to do a recursive diff here.
6754 vector<Command*> cmds;
6756 _session->add_commands (cmds);
6758 _session->add_command (new StatefulDiffCommand (pl));
6762 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6763 set_selected_regionview_from_region_list ((*i), Selection::Add);
6769 Editor::place_transient()
6775 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6781 framepos_t where = get_preferred_edit_position();
6783 begin_reversible_command (_("place transient"));
6785 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6786 framepos_t position = (*r)->region()->position();
6787 (*r)->region()->add_transient(where - position);
6790 commit_reversible_command ();
6794 Editor::remove_transient(ArdourCanvas::Item* item)
6800 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6803 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6804 _arv->remove_transient (*(float*) _line->get_data ("position"));
6808 Editor::snap_regions_to_grid ()
6810 list <boost::shared_ptr<Playlist > > used_playlists;
6812 RegionSelection rs = get_regions_from_selection_and_entered ();
6814 if (!_session || rs.empty()) {
6818 begin_reversible_command (_("snap regions to grid"));
6820 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6822 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6824 if (!pl->frozen()) {
6825 /* we haven't seen this playlist before */
6827 /* remember used playlists so we can thaw them later */
6828 used_playlists.push_back(pl);
6832 framepos_t start_frame = (*r)->region()->first_frame ();
6833 snap_to (start_frame);
6834 (*r)->region()->set_position (start_frame);
6837 while (used_playlists.size() > 0) {
6838 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6840 used_playlists.pop_front();
6843 commit_reversible_command ();
6847 Editor::close_region_gaps ()
6849 list <boost::shared_ptr<Playlist > > used_playlists;
6851 RegionSelection rs = get_regions_from_selection_and_entered ();
6853 if (!_session || rs.empty()) {
6857 Dialog dialog (_("Close Region Gaps"));
6860 table.set_spacings (12);
6861 table.set_border_width (12);
6862 Label* l = manage (left_aligned_label (_("Crossfade length")));
6863 table.attach (*l, 0, 1, 0, 1);
6865 SpinButton spin_crossfade (1, 0);
6866 spin_crossfade.set_range (0, 15);
6867 spin_crossfade.set_increments (1, 1);
6868 spin_crossfade.set_value (5);
6869 table.attach (spin_crossfade, 1, 2, 0, 1);
6871 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6873 l = manage (left_aligned_label (_("Pull-back length")));
6874 table.attach (*l, 0, 1, 1, 2);
6876 SpinButton spin_pullback (1, 0);
6877 spin_pullback.set_range (0, 100);
6878 spin_pullback.set_increments (1, 1);
6879 spin_pullback.set_value(30);
6880 table.attach (spin_pullback, 1, 2, 1, 2);
6882 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6884 dialog.get_vbox()->pack_start (table);
6885 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6886 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6889 if (dialog.run () == RESPONSE_CANCEL) {
6893 framepos_t crossfade_len = spin_crossfade.get_value();
6894 framepos_t pull_back_frames = spin_pullback.get_value();
6896 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6897 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6899 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6901 begin_reversible_command (_("close region gaps"));
6904 boost::shared_ptr<Region> last_region;
6906 rs.sort_by_position_and_track();
6908 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6910 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6912 if (!pl->frozen()) {
6913 /* we haven't seen this playlist before */
6915 /* remember used playlists so we can thaw them later */
6916 used_playlists.push_back(pl);
6920 framepos_t position = (*r)->region()->position();
6922 if (idx == 0 || position < last_region->position()){
6923 last_region = (*r)->region();
6928 (*r)->region()->trim_front( (position - pull_back_frames));
6929 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6931 last_region = (*r)->region();
6936 while (used_playlists.size() > 0) {
6937 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6939 used_playlists.pop_front();
6942 commit_reversible_command ();
6946 Editor::tab_to_transient (bool forward)
6948 AnalysisFeatureList positions;
6950 RegionSelection rs = get_regions_from_selection_and_entered ();
6956 framepos_t pos = _session->audible_frame ();
6958 if (!selection->tracks.empty()) {
6960 /* don't waste time searching for transients in duplicate playlists.
6963 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6965 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6967 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6970 boost::shared_ptr<Track> tr = rtv->track();
6972 boost::shared_ptr<Playlist> pl = tr->playlist ();
6974 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6977 positions.push_back (result);
6990 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6991 (*r)->region()->get_transients (positions);
6995 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6998 AnalysisFeatureList::iterator x;
7000 for (x = positions.begin(); x != positions.end(); ++x) {
7006 if (x != positions.end ()) {
7007 _session->request_locate (*x);
7011 AnalysisFeatureList::reverse_iterator x;
7013 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7019 if (x != positions.rend ()) {
7020 _session->request_locate (*x);
7026 Editor::playhead_forward_to_grid ()
7032 framepos_t pos = playhead_cursor->current_frame ();
7033 if (pos < max_framepos - 1) {
7035 snap_to_internal (pos, RoundUpAlways, false);
7036 _session->request_locate (pos);
7042 Editor::playhead_backward_to_grid ()
7048 framepos_t pos = playhead_cursor->current_frame ();
7051 snap_to_internal (pos, RoundDownAlways, false);
7052 _session->request_locate (pos);
7057 Editor::set_track_height (Height h)
7059 TrackSelection& ts (selection->tracks);
7061 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7062 (*x)->set_height_enum (h);
7067 Editor::toggle_tracks_active ()
7069 TrackSelection& ts (selection->tracks);
7071 bool target = false;
7077 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7078 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7082 target = !rtv->_route->active();
7085 rtv->_route->set_active (target, this);
7091 Editor::remove_tracks ()
7093 /* this will delete GUI objects that may be the subject of an event
7094 handler in which this method is called. Defer actual deletion to the
7095 next idle callback, when all event handling is finished.
7097 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7101 Editor::idle_remove_tracks ()
7104 return false; /* do not call again */
7108 Editor::_remove_tracks ()
7110 TrackSelection& ts (selection->tracks);
7116 vector<string> choices;
7120 const char* trackstr;
7122 vector<boost::shared_ptr<Route> > routes;
7123 bool special_bus = false;
7125 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7126 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7130 if (rtv->is_track()) {
7135 routes.push_back (rtv->_route);
7137 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7142 if (special_bus && !Config->get_allow_special_bus_removal()) {
7143 MessageDialog msg (_("That would be bad news ...."),
7147 msg.set_secondary_text (string_compose (_(
7148 "Removing the master or monitor bus is such a bad idea\n\
7149 that %1 is not going to allow it.\n\
7151 If you really want to do this sort of thing\n\
7152 edit your ardour.rc file to set the\n\
7153 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7160 if (ntracks + nbusses == 0) {
7164 trackstr = P_("track", "tracks", ntracks);
7165 busstr = P_("bus", "busses", nbusses);
7169 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7170 "(You may also lose the playlists associated with the %2)\n\n"
7171 "This action cannot be undone, and the session file will be overwritten!"),
7172 ntracks, trackstr, nbusses, busstr);
7174 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7175 "(You may also lose the playlists associated with the %2)\n\n"
7176 "This action cannot be undone, and the session file will be overwritten!"),
7179 } else if (nbusses) {
7180 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7181 "This action cannot be undone, and the session file will be overwritten"),
7185 choices.push_back (_("No, do nothing."));
7186 if (ntracks + nbusses > 1) {
7187 choices.push_back (_("Yes, remove them."));
7189 choices.push_back (_("Yes, remove it."));
7194 title = string_compose (_("Remove %1"), trackstr);
7196 title = string_compose (_("Remove %1"), busstr);
7199 Choice prompter (title, prompt, choices);
7201 if (prompter.run () != 1) {
7206 Session::StateProtector sp (_session);
7207 DisplaySuspender ds;
7208 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7209 _session->remove_route (*x);
7215 Editor::do_insert_time ()
7217 if (selection->tracks.empty()) {
7221 InsertRemoveTimeDialog d (*this);
7222 int response = d.run ();
7224 if (response != RESPONSE_OK) {
7228 if (d.distance() == 0) {
7232 InsertTimeOption opt = d.intersected_region_action ();
7235 get_preferred_edit_position(),
7241 d.move_glued_markers(),
7242 d.move_locked_markers(),
7248 Editor::insert_time (
7249 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7250 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7254 if (Config->get_edit_mode() == Lock) {
7257 bool in_command = false;
7259 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7261 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7265 /* don't operate on any playlist more than once, which could
7266 * happen if "all playlists" is enabled, but there is more
7267 * than 1 track using playlists "from" a given track.
7270 set<boost::shared_ptr<Playlist> > pl;
7272 if (all_playlists) {
7273 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7274 if (rtav && rtav->track ()) {
7275 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7276 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7281 if ((*x)->playlist ()) {
7282 pl.insert ((*x)->playlist ());
7286 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7288 (*i)->clear_changes ();
7289 (*i)->clear_owned_changes ();
7291 if (opt == SplitIntersected) {
7295 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7298 begin_reversible_command (_("insert time"));
7301 vector<Command*> cmds;
7303 _session->add_commands (cmds);
7305 _session->add_command (new StatefulDiffCommand (*i));
7309 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7312 begin_reversible_command (_("insert time"));
7315 rtav->route ()->shift (pos, frames);
7322 XMLNode& before (_session->locations()->get_state());
7323 Locations::LocationList copy (_session->locations()->list());
7325 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7327 Locations::LocationList::const_iterator tmp;
7329 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7330 bool const was_locked = (*i)->locked ();
7331 if (locked_markers_too) {
7335 if ((*i)->start() >= pos) {
7336 // move end first, in case we're moving by more than the length of the range
7337 if (!(*i)->is_mark()) {
7338 (*i)->set_end ((*i)->end() + frames);
7340 (*i)->set_start ((*i)->start() + frames);
7352 begin_reversible_command (_("insert time"));
7355 XMLNode& after (_session->locations()->get_state());
7356 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7362 begin_reversible_command (_("insert time"));
7365 XMLNode& before (_session->tempo_map().get_state());
7366 _session->tempo_map().insert_time (pos, frames);
7367 XMLNode& after (_session->tempo_map().get_state());
7368 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7372 commit_reversible_command ();
7377 Editor::do_remove_time ()
7379 if (selection->tracks.empty()) {
7383 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7384 InsertRemoveTimeDialog d (*this, true);
7386 int response = d.run ();
7388 if (response != RESPONSE_OK) {
7392 framecnt_t distance = d.distance();
7394 if (distance == 0) {
7404 d.move_glued_markers(),
7405 d.move_locked_markers(),
7411 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7412 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7414 if (Config->get_edit_mode() == Lock) {
7415 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7418 bool in_command = false;
7420 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7422 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7426 XMLNode &before = pl->get_state();
7428 std::list<AudioRange> rl;
7429 AudioRange ar(pos, pos+frames, 0);
7432 pl->shift (pos, -frames, true, ignore_music_glue);
7435 begin_reversible_command (_("cut time"));
7438 XMLNode &after = pl->get_state();
7440 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7444 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7447 begin_reversible_command (_("cut time"));
7450 rtav->route ()->shift (pos, -frames);
7454 std::list<Location*> loc_kill_list;
7459 XMLNode& before (_session->locations()->get_state());
7460 Locations::LocationList copy (_session->locations()->list());
7462 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7463 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7465 bool const was_locked = (*i)->locked ();
7466 if (locked_markers_too) {
7470 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7471 if ((*i)->end() >= pos
7472 && (*i)->end() < pos+frames
7473 && (*i)->start() >= pos
7474 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7476 loc_kill_list.push_back(*i);
7477 } else { // only start or end is included, try to do the right thing
7478 // move start before moving end, to avoid trying to move the end to before the start
7479 // if we're removing more time than the length of the range
7480 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7481 // start is within cut
7482 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7484 } else if ((*i)->start() >= pos+frames) {
7485 // start (and thus entire range) lies beyond end of cut
7486 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7489 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7490 // end is inside cut
7491 (*i)->set_end (pos); // bring the end to the cut
7493 } else if ((*i)->end() >= pos+frames) {
7494 // end is beyond end of cut
7495 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7500 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7501 loc_kill_list.push_back(*i);
7503 } else if ((*i)->start() >= pos) {
7504 (*i)->set_start ((*i)->start() -frames);
7514 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7515 _session->locations()->remove( *i );
7520 begin_reversible_command (_("cut time"));
7523 XMLNode& after (_session->locations()->get_state());
7524 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7529 XMLNode& before (_session->tempo_map().get_state());
7531 if (_session->tempo_map().remove_time (pos, frames) ) {
7533 begin_reversible_command (_("remove time"));
7536 XMLNode& after (_session->tempo_map().get_state());
7537 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7542 commit_reversible_command ();
7547 Editor::fit_selection ()
7549 if (!selection->tracks.empty()) {
7550 fit_tracks (selection->tracks);
7554 /* no selected tracks - use tracks with selected regions */
7556 if (!selection->regions.empty()) {
7557 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7558 tvl.push_back (&(*r)->get_time_axis_view ());
7564 } else if (internal_editing()) {
7565 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7568 if (entered_track) {
7569 tvl.push_back (entered_track);
7578 Editor::fit_tracks (TrackViewList & tracks)
7580 if (tracks.empty()) {
7584 uint32_t child_heights = 0;
7585 int visible_tracks = 0;
7587 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7589 if (!(*t)->marked_for_display()) {
7593 child_heights += (*t)->effective_height() - (*t)->current_height();
7597 /* compute the per-track height from:
7599 total canvas visible height -
7600 height that will be taken by visible children of selected
7601 tracks - height of the ruler/hscroll area
7603 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7604 double first_y_pos = DBL_MAX;
7606 if (h < TimeAxisView::preset_height (HeightSmall)) {
7607 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7608 /* too small to be displayed */
7612 undo_visual_stack.push_back (current_visual_state (true));
7613 PBD::Unwinder<bool> nsv (no_save_visual, true);
7615 /* build a list of all tracks, including children */
7618 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7620 TimeAxisView::Children c = (*i)->get_child_list ();
7621 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7622 all.push_back (j->get());
7627 // find selection range.
7628 // if someone knows how to user TrackViewList::iterator for this
7630 int selected_top = -1;
7631 int selected_bottom = -1;
7633 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7634 if ((*t)->marked_for_display ()) {
7635 if (tracks.contains(*t)) {
7636 if (selected_top == -1) {
7639 selected_bottom = i;
7645 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7646 if ((*t)->marked_for_display ()) {
7647 if (tracks.contains(*t)) {
7648 (*t)->set_height (h);
7649 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7651 if (i > selected_top && i < selected_bottom) {
7652 hide_track_in_display (*t);
7659 set the controls_layout height now, because waiting for its size
7660 request signal handler will cause the vertical adjustment setting to fail
7663 controls_layout.property_height () = _full_canvas_height;
7664 vertical_adjustment.set_value (first_y_pos);
7666 redo_visual_stack.push_back (current_visual_state (true));
7668 visible_tracks_selector.set_text (_("Sel"));
7672 Editor::save_visual_state (uint32_t n)
7674 while (visual_states.size() <= n) {
7675 visual_states.push_back (0);
7678 if (visual_states[n] != 0) {
7679 delete visual_states[n];
7682 visual_states[n] = current_visual_state (true);
7687 Editor::goto_visual_state (uint32_t n)
7689 if (visual_states.size() <= n) {
7693 if (visual_states[n] == 0) {
7697 use_visual_state (*visual_states[n]);
7701 Editor::start_visual_state_op (uint32_t n)
7703 save_visual_state (n);
7705 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7707 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7708 pup->set_text (buf);
7713 Editor::cancel_visual_state_op (uint32_t n)
7715 goto_visual_state (n);
7719 Editor::toggle_region_mute ()
7721 if (_ignore_region_action) {
7725 RegionSelection rs = get_regions_from_selection_and_entered ();
7731 if (rs.size() > 1) {
7732 begin_reversible_command (_("mute regions"));
7734 begin_reversible_command (_("mute region"));
7737 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7739 (*i)->region()->playlist()->clear_changes ();
7740 (*i)->region()->set_muted (!(*i)->region()->muted ());
7741 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7745 commit_reversible_command ();
7749 Editor::combine_regions ()
7751 /* foreach track with selected regions, take all selected regions
7752 and join them into a new region containing the subregions (as a
7756 typedef set<RouteTimeAxisView*> RTVS;
7759 if (selection->regions.empty()) {
7763 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7764 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7767 tracks.insert (rtv);
7771 begin_reversible_command (_("combine regions"));
7773 vector<RegionView*> new_selection;
7775 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7778 if ((rv = (*i)->combine_regions ()) != 0) {
7779 new_selection.push_back (rv);
7783 selection->clear_regions ();
7784 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7785 selection->add (*i);
7788 commit_reversible_command ();
7792 Editor::uncombine_regions ()
7794 typedef set<RouteTimeAxisView*> RTVS;
7797 if (selection->regions.empty()) {
7801 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7802 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7805 tracks.insert (rtv);
7809 begin_reversible_command (_("uncombine regions"));
7811 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7812 (*i)->uncombine_regions ();
7815 commit_reversible_command ();
7819 Editor::toggle_midi_input_active (bool flip_others)
7822 boost::shared_ptr<RouteList> rl (new RouteList);
7824 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7825 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7831 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7834 rl->push_back (rtav->route());
7835 onoff = !mt->input_active();
7839 _session->set_exclusive_input_active (rl, onoff, flip_others);
7846 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7848 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7849 lock_dialog->get_vbox()->pack_start (*padlock);
7851 ArdourButton* b = manage (new ArdourButton);
7852 b->set_name ("lock button");
7853 b->set_text (_("Click to unlock"));
7854 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7855 lock_dialog->get_vbox()->pack_start (*b);
7857 lock_dialog->get_vbox()->show_all ();
7858 lock_dialog->set_size_request (200, 200);
7861 delete _main_menu_disabler;
7862 _main_menu_disabler = new MainMenuDisabler;
7864 lock_dialog->present ();
7870 lock_dialog->hide ();
7872 delete _main_menu_disabler;
7873 _main_menu_disabler = 0;
7875 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7876 start_lock_event_timing ();
7881 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7883 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7887 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7889 Timers::TimerSuspender t;
7890 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7891 Gtkmm2ext::UI::instance()->flush_pending ();
7895 Editor::bring_all_sources_into_session ()
7902 ArdourDialog w (_("Moving embedded files into session folder"));
7903 w.get_vbox()->pack_start (msg);
7906 /* flush all pending GUI events because we're about to start copying
7910 Timers::TimerSuspender t;
7911 Gtkmm2ext::UI::instance()->flush_pending ();
7915 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));