2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/boost_debug.h"
46 #include "ardour/dB.h"
47 #include "ardour/location.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/operations.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/profile.h"
53 #include "ardour/quantize.h"
54 #include "ardour/legatize.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/reverse.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/strip_silence.h"
60 #include "ardour/transient_detector.h"
61 #include "ardour/transpose.h"
63 #include "canvas/canvas.h"
66 #include "audio_region_view.h"
67 #include "audio_streamview.h"
68 #include "audio_time_axis.h"
69 #include "automation_region_view.h"
70 #include "automation_time_axis.h"
71 #include "control_point.h"
75 #include "editor_cursors.h"
76 #include "editor_drag.h"
77 #include "editor_regions.h"
78 #include "editor_routes.h"
79 #include "gui_thread.h"
80 #include "insert_remove_time_dialog.h"
81 #include "interthread_progress_window.h"
82 #include "item_counts.h"
84 #include "midi_region_view.h"
85 #include "mixer_strip.h"
86 #include "mouse_cursors.h"
87 #include "normalize_dialog.h"
89 #include "paste_context.h"
90 #include "patch_change_dialog.h"
91 #include "quantize_dialog.h"
92 #include "region_gain_line.h"
93 #include "rgb_macros.h"
94 #include "route_time_axis.h"
95 #include "selection.h"
96 #include "selection_templates.h"
97 #include "streamview.h"
98 #include "strip_silence_dialog.h"
99 #include "time_axis_view.h"
101 #include "transpose_dialog.h"
102 #include "transform_dialog.h"
103 #include "ui_config.h"
108 using namespace ARDOUR;
111 using namespace Gtkmm2ext;
112 using namespace Editing;
113 using Gtkmm2ext::Keyboard;
115 /***********************************************************************
117 ***********************************************************************/
120 Editor::undo (uint32_t n)
122 if (_drags->active ()) {
128 if (_session->undo_depth() == 0) {
129 undo_action->set_sensitive(false);
131 redo_action->set_sensitive(true);
132 begin_selection_op_history ();
137 Editor::redo (uint32_t n)
139 if (_drags->active ()) {
145 if (_session->redo_depth() == 0) {
146 redo_action->set_sensitive(false);
148 undo_action->set_sensitive(true);
149 begin_selection_op_history ();
154 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
156 RegionSelection pre_selected_regions = selection->regions;
157 bool working_on_selection = !pre_selected_regions.empty();
159 list<boost::shared_ptr<Playlist> > used_playlists;
160 list<RouteTimeAxisView*> used_trackviews;
162 if (regions.empty()) {
166 begin_reversible_command (_("split"));
168 // if splitting a single region, and snap-to is using
169 // region boundaries, don't pay attention to them
171 if (regions.size() == 1) {
172 switch (_snap_type) {
173 case SnapToRegionStart:
174 case SnapToRegionSync:
175 case SnapToRegionEnd:
185 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
187 RegionSelection::iterator tmp;
189 /* XXX this test needs to be more complicated, to make sure we really
190 have something to split.
193 if (!(*a)->region()->covers (where)) {
201 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
209 /* we haven't seen this playlist before */
211 /* remember used playlists so we can thaw them later */
212 used_playlists.push_back(pl);
214 TimeAxisView& tv = (*a)->get_time_axis_view();
215 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
217 used_trackviews.push_back (rtv);
224 pl->clear_changes ();
225 pl->split_region ((*a)->region(), where);
226 _session->add_command (new StatefulDiffCommand (pl));
232 latest_regionviews.clear ();
234 vector<sigc::connection> region_added_connections;
236 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
237 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
240 while (used_playlists.size() > 0) {
241 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
243 used_playlists.pop_front();
246 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
250 if (working_on_selection) {
251 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
253 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
254 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
255 /* There are three classes of regions that we might want selected after
256 splitting selected regions:
257 - regions selected before the split operation, and unaffected by it
258 - newly-created regions before the split
259 - newly-created regions after the split
262 if (rsas & Existing) {
263 // region selections that existed before the split.
264 selection->add ( pre_selected_regions );
267 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
268 if ((*ri)->region()->position() < where) {
269 // new regions created before the split
270 if (rsas & NewlyCreatedLeft) {
271 selection->add (*ri);
274 // new regions created after the split
275 if (rsas & NewlyCreatedRight) {
276 selection->add (*ri);
280 _ignore_follow_edits = false;
282 _ignore_follow_edits = true;
283 if( working_on_selection ) {
284 selection->add (latest_regionviews); //these are the new regions created after the split
286 _ignore_follow_edits = false;
289 commit_reversible_command ();
292 /** Move one extreme of the current range selection. If more than one range is selected,
293 * the start of the earliest range or the end of the latest range is moved.
295 * @param move_end true to move the end of the current range selection, false to move
297 * @param next true to move the extreme to the next region boundary, false to move to
301 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
303 if (selection->time.start() == selection->time.end_frame()) {
307 framepos_t start = selection->time.start ();
308 framepos_t end = selection->time.end_frame ();
310 /* the position of the thing we may move */
311 framepos_t pos = move_end ? end : start;
312 int dir = next ? 1 : -1;
314 /* so we don't find the current region again */
315 if (dir > 0 || pos > 0) {
319 framepos_t const target = get_region_boundary (pos, dir, true, false);
334 begin_reversible_selection_op (_("alter selection"));
335 selection->set_preserving_all_ranges (start, end);
336 commit_reversible_selection_op ();
340 Editor::nudge_forward_release (GdkEventButton* ev)
342 if (ev->state & Keyboard::PrimaryModifier) {
343 nudge_forward (false, true);
345 nudge_forward (false, false);
351 Editor::nudge_backward_release (GdkEventButton* ev)
353 if (ev->state & Keyboard::PrimaryModifier) {
354 nudge_backward (false, true);
356 nudge_backward (false, false);
363 Editor::nudge_forward (bool next, bool force_playhead)
366 framepos_t next_distance;
372 RegionSelection rs = get_regions_from_selection_and_entered ();
374 if (!force_playhead && !rs.empty()) {
376 begin_reversible_command (_("nudge regions forward"));
378 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
379 boost::shared_ptr<Region> r ((*i)->region());
381 distance = get_nudge_distance (r->position(), next_distance);
384 distance = next_distance;
388 r->set_position (r->position() + distance);
389 _session->add_command (new StatefulDiffCommand (r));
392 commit_reversible_command ();
395 } else if (!force_playhead && !selection->markers.empty()) {
398 bool in_command = false;
400 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
402 Location* loc = find_location_from_marker ((*i), is_start);
406 XMLNode& before (loc->get_state());
409 distance = get_nudge_distance (loc->start(), next_distance);
411 distance = next_distance;
413 if (max_framepos - distance > loc->start() + loc->length()) {
414 loc->set_start (loc->start() + distance);
416 loc->set_start (max_framepos - loc->length());
419 distance = get_nudge_distance (loc->end(), next_distance);
421 distance = next_distance;
423 if (max_framepos - distance > loc->end()) {
424 loc->set_end (loc->end() + distance);
426 loc->set_end (max_framepos);
430 begin_reversible_command (_("nudge location forward"));
433 XMLNode& after (loc->get_state());
434 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
439 commit_reversible_command ();
442 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
443 _session->request_locate (playhead_cursor->current_frame () + distance);
448 Editor::nudge_backward (bool next, bool force_playhead)
451 framepos_t next_distance;
457 RegionSelection rs = get_regions_from_selection_and_entered ();
459 if (!force_playhead && !rs.empty()) {
461 begin_reversible_command (_("nudge regions backward"));
463 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
464 boost::shared_ptr<Region> r ((*i)->region());
466 distance = get_nudge_distance (r->position(), next_distance);
469 distance = next_distance;
474 if (r->position() > distance) {
475 r->set_position (r->position() - distance);
479 _session->add_command (new StatefulDiffCommand (r));
482 commit_reversible_command ();
484 } else if (!force_playhead && !selection->markers.empty()) {
487 bool in_command = false;
489 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
491 Location* loc = find_location_from_marker ((*i), is_start);
495 XMLNode& before (loc->get_state());
498 distance = get_nudge_distance (loc->start(), next_distance);
500 distance = next_distance;
502 if (distance < loc->start()) {
503 loc->set_start (loc->start() - distance);
508 distance = get_nudge_distance (loc->end(), next_distance);
511 distance = next_distance;
514 if (distance < loc->end() - loc->length()) {
515 loc->set_end (loc->end() - distance);
517 loc->set_end (loc->length());
521 begin_reversible_command (_("nudge location forward"));
524 XMLNode& after (loc->get_state());
525 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
529 commit_reversible_command ();
534 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
536 if (playhead_cursor->current_frame () > distance) {
537 _session->request_locate (playhead_cursor->current_frame () - distance);
539 _session->goto_start();
545 Editor::nudge_forward_capture_offset ()
547 RegionSelection rs = get_regions_from_selection_and_entered ();
549 if (!_session || rs.empty()) {
553 begin_reversible_command (_("nudge forward"));
555 framepos_t const distance = _session->worst_output_latency();
557 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
558 boost::shared_ptr<Region> r ((*i)->region());
561 r->set_position (r->position() + distance);
562 _session->add_command(new StatefulDiffCommand (r));
565 commit_reversible_command ();
569 Editor::nudge_backward_capture_offset ()
571 RegionSelection rs = get_regions_from_selection_and_entered ();
573 if (!_session || rs.empty()) {
577 begin_reversible_command (_("nudge backward"));
579 framepos_t const distance = _session->worst_output_latency();
581 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
582 boost::shared_ptr<Region> r ((*i)->region());
586 if (r->position() > distance) {
587 r->set_position (r->position() - distance);
591 _session->add_command(new StatefulDiffCommand (r));
594 commit_reversible_command ();
597 struct RegionSelectionPositionSorter {
598 bool operator() (RegionView* a, RegionView* b) {
599 return a->region()->position() < b->region()->position();
604 Editor::sequence_regions ()
607 framepos_t r_end_prev;
615 RegionSelection rs = get_regions_from_selection_and_entered ();
616 rs.sort(RegionSelectionPositionSorter());
620 bool in_command = false;
622 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
623 boost::shared_ptr<Region> r ((*i)->region());
631 if(r->position_locked())
638 r->set_position(r_end_prev);
642 begin_reversible_command (_("sequence regions"));
645 _session->add_command (new StatefulDiffCommand (r));
647 r_end=r->position() + r->length();
653 commit_reversible_command ();
662 Editor::move_to_start ()
664 _session->goto_start ();
668 Editor::move_to_end ()
671 _session->request_locate (_session->current_end_frame());
675 Editor::build_region_boundary_cache ()
678 vector<RegionPoint> interesting_points;
679 boost::shared_ptr<Region> r;
680 TrackViewList tracks;
683 region_boundary_cache.clear ();
689 switch (_snap_type) {
690 case SnapToRegionStart:
691 interesting_points.push_back (Start);
693 case SnapToRegionEnd:
694 interesting_points.push_back (End);
696 case SnapToRegionSync:
697 interesting_points.push_back (SyncPoint);
699 case SnapToRegionBoundary:
700 interesting_points.push_back (Start);
701 interesting_points.push_back (End);
704 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
705 abort(); /*NOTREACHED*/
709 TimeAxisView *ontrack = 0;
712 if (!selection->tracks.empty()) {
713 tlist = selection->tracks.filter_to_unique_playlists ();
715 tlist = track_views.filter_to_unique_playlists ();
718 while (pos < _session->current_end_frame() && !at_end) {
721 framepos_t lpos = max_framepos;
723 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
725 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
726 if (*p == interesting_points.back()) {
729 /* move to next point type */
735 rpos = r->first_frame();
739 rpos = r->last_frame();
743 rpos = r->sync_position ();
751 RouteTimeAxisView *rtav;
753 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
754 if (rtav->track() != 0) {
755 speed = rtav->track()->speed();
759 rpos = track_frame_to_session_frame (rpos, speed);
765 /* prevent duplicates, but we don't use set<> because we want to be able
769 vector<framepos_t>::iterator ri;
771 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
777 if (ri == region_boundary_cache.end()) {
778 region_boundary_cache.push_back (rpos);
785 /* finally sort to be sure that the order is correct */
787 sort (region_boundary_cache.begin(), region_boundary_cache.end());
790 boost::shared_ptr<Region>
791 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
793 TrackViewList::iterator i;
794 framepos_t closest = max_framepos;
795 boost::shared_ptr<Region> ret;
799 framepos_t track_frame;
800 RouteTimeAxisView *rtav;
802 for (i = tracks.begin(); i != tracks.end(); ++i) {
805 boost::shared_ptr<Region> r;
808 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
809 if (rtav->track()!=0)
810 track_speed = rtav->track()->speed();
813 track_frame = session_frame_to_track_frame(frame, track_speed);
815 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
821 rpos = r->first_frame ();
825 rpos = r->last_frame ();
829 rpos = r->sync_position ();
833 // rpos is a "track frame", converting it to "_session frame"
834 rpos = track_frame_to_session_frame(rpos, track_speed);
837 distance = rpos - frame;
839 distance = frame - rpos;
842 if (distance < closest) {
854 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
856 framecnt_t distance = max_framepos;
857 framepos_t current_nearest = -1;
859 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
860 framepos_t contender;
863 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
869 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
873 d = ::llabs (pos - contender);
876 current_nearest = contender;
881 return current_nearest;
885 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
890 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
892 if (!selection->tracks.empty()) {
894 target = find_next_region_boundary (pos, dir, selection->tracks);
898 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
899 get_onscreen_tracks (tvl);
900 target = find_next_region_boundary (pos, dir, tvl);
902 target = find_next_region_boundary (pos, dir, track_views);
908 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
909 get_onscreen_tracks (tvl);
910 target = find_next_region_boundary (pos, dir, tvl);
912 target = find_next_region_boundary (pos, dir, track_views);
920 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
922 framepos_t pos = playhead_cursor->current_frame ();
929 // so we don't find the current region again..
930 if (dir > 0 || pos > 0) {
934 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
938 _session->request_locate (target);
942 Editor::cursor_to_next_region_boundary (bool with_selection)
944 cursor_to_region_boundary (with_selection, 1);
948 Editor::cursor_to_previous_region_boundary (bool with_selection)
950 cursor_to_region_boundary (with_selection, -1);
954 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
956 boost::shared_ptr<Region> r;
957 framepos_t pos = cursor->current_frame ();
963 TimeAxisView *ontrack = 0;
965 // so we don't find the current region again..
969 if (!selection->tracks.empty()) {
971 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
973 } else if (clicked_axisview) {
976 t.push_back (clicked_axisview);
978 r = find_next_region (pos, point, dir, t, &ontrack);
982 r = find_next_region (pos, point, dir, track_views, &ontrack);
991 pos = r->first_frame ();
995 pos = r->last_frame ();
999 pos = r->sync_position ();
1004 RouteTimeAxisView *rtav;
1006 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1007 if (rtav->track() != 0) {
1008 speed = rtav->track()->speed();
1012 pos = track_frame_to_session_frame(pos, speed);
1014 if (cursor == playhead_cursor) {
1015 _session->request_locate (pos);
1017 cursor->set_position (pos);
1022 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1024 cursor_to_region_point (cursor, point, 1);
1028 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1030 cursor_to_region_point (cursor, point, -1);
1034 Editor::cursor_to_selection_start (EditorCursor *cursor)
1038 switch (mouse_mode) {
1040 if (!selection->regions.empty()) {
1041 pos = selection->regions.start();
1046 if (!selection->time.empty()) {
1047 pos = selection->time.start ();
1055 if (cursor == playhead_cursor) {
1056 _session->request_locate (pos);
1058 cursor->set_position (pos);
1063 Editor::cursor_to_selection_end (EditorCursor *cursor)
1067 switch (mouse_mode) {
1069 if (!selection->regions.empty()) {
1070 pos = selection->regions.end_frame();
1075 if (!selection->time.empty()) {
1076 pos = selection->time.end_frame ();
1084 if (cursor == playhead_cursor) {
1085 _session->request_locate (pos);
1087 cursor->set_position (pos);
1092 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1102 if (selection->markers.empty()) {
1106 if (!mouse_frame (mouse, ignored)) {
1110 add_location_mark (mouse);
1113 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1117 framepos_t pos = loc->start();
1119 // so we don't find the current region again..
1120 if (dir > 0 || pos > 0) {
1124 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1128 loc->move_to (target);
1132 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1134 selected_marker_to_region_boundary (with_selection, 1);
1138 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1140 selected_marker_to_region_boundary (with_selection, -1);
1144 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1146 boost::shared_ptr<Region> r;
1151 if (!_session || selection->markers.empty()) {
1155 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1159 TimeAxisView *ontrack = 0;
1163 // so we don't find the current region again..
1167 if (!selection->tracks.empty()) {
1169 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1173 r = find_next_region (pos, point, dir, track_views, &ontrack);
1182 pos = r->first_frame ();
1186 pos = r->last_frame ();
1190 pos = r->adjust_to_sync (r->first_frame());
1195 RouteTimeAxisView *rtav;
1197 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1198 if (rtav->track() != 0) {
1199 speed = rtav->track()->speed();
1203 pos = track_frame_to_session_frame(pos, speed);
1209 Editor::selected_marker_to_next_region_point (RegionPoint point)
1211 selected_marker_to_region_point (point, 1);
1215 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1217 selected_marker_to_region_point (point, -1);
1221 Editor::selected_marker_to_selection_start ()
1227 if (!_session || selection->markers.empty()) {
1231 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1235 switch (mouse_mode) {
1237 if (!selection->regions.empty()) {
1238 pos = selection->regions.start();
1243 if (!selection->time.empty()) {
1244 pos = selection->time.start ();
1256 Editor::selected_marker_to_selection_end ()
1262 if (!_session || selection->markers.empty()) {
1266 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1270 switch (mouse_mode) {
1272 if (!selection->regions.empty()) {
1273 pos = selection->regions.end_frame();
1278 if (!selection->time.empty()) {
1279 pos = selection->time.end_frame ();
1291 Editor::scroll_playhead (bool forward)
1293 framepos_t pos = playhead_cursor->current_frame ();
1294 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1297 if (pos == max_framepos) {
1301 if (pos < max_framepos - delta) {
1320 _session->request_locate (pos);
1324 Editor::cursor_align (bool playhead_to_edit)
1330 if (playhead_to_edit) {
1332 if (selection->markers.empty()) {
1336 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1339 /* move selected markers to playhead */
1341 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1344 Location* loc = find_location_from_marker (*i, ignored);
1346 if (loc->is_mark()) {
1347 loc->set_start (playhead_cursor->current_frame ());
1349 loc->set (playhead_cursor->current_frame (),
1350 playhead_cursor->current_frame () + loc->length());
1357 Editor::scroll_backward (float pages)
1359 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1360 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1363 if (leftmost_frame < cnt) {
1366 frame = leftmost_frame - cnt;
1369 reset_x_origin (frame);
1373 Editor::scroll_forward (float pages)
1375 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1376 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1379 if (max_framepos - cnt < leftmost_frame) {
1380 frame = max_framepos - cnt;
1382 frame = leftmost_frame + cnt;
1385 reset_x_origin (frame);
1389 Editor::scroll_tracks_down ()
1391 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1392 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1393 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1396 vertical_adjustment.set_value (vert_value);
1400 Editor::scroll_tracks_up ()
1402 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1406 Editor::scroll_tracks_down_line ()
1408 double vert_value = vertical_adjustment.get_value() + 60;
1410 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1411 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1414 vertical_adjustment.set_value (vert_value);
1418 Editor::scroll_tracks_up_line ()
1420 reset_y_origin (vertical_adjustment.get_value() - 60);
1424 Editor::scroll_down_one_track (bool skip_child_views)
1426 TrackViewList::reverse_iterator next = track_views.rend();
1427 const double top_of_trackviews = vertical_adjustment.get_value();
1429 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1430 if ((*t)->hidden()) {
1434 /* If this is the upper-most visible trackview, we want to display
1435 * the one above it (next)
1437 * Note that covers_y_position() is recursive and includes child views
1439 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1442 if (skip_child_views) {
1445 /* automation lane (one level, non-recursive)
1447 * - if no automation lane exists -> move to next tack
1448 * - if the first (here: bottom-most) matches -> move to next tack
1449 * - if no y-axis match is found -> the current track is at the top
1450 * -> move to last (here: top-most) automation lane
1452 TimeAxisView::Children kids = (*t)->get_child_list();
1453 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1455 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1456 if ((*ci)->hidden()) {
1460 std::pair<TimeAxisView*,double> dev;
1461 dev = (*ci)->covers_y_position (top_of_trackviews);
1463 /* some automation lane is currently at the top */
1464 if (ci == kids.rbegin()) {
1465 /* first (bottom-most) autmation lane is at the top.
1466 * -> move to next track
1475 if (nkid != kids.rend()) {
1476 ensure_time_axis_view_is_visible (**nkid, true);
1484 /* move to the track below the first one that covers the */
1486 if (next != track_views.rend()) {
1487 ensure_time_axis_view_is_visible (**next, true);
1495 Editor::scroll_up_one_track (bool skip_child_views)
1497 TrackViewList::iterator prev = track_views.end();
1498 double top_of_trackviews = vertical_adjustment.get_value ();
1500 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1502 if ((*t)->hidden()) {
1506 /* find the trackview at the top of the trackview group
1508 * Note that covers_y_position() is recursive and includes child views
1510 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1513 if (skip_child_views) {
1516 /* automation lane (one level, non-recursive)
1518 * - if no automation lane exists -> move to prev tack
1519 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1520 * (actually last automation lane of previous track, see below)
1521 * - if first (top-most) lane is at the top -> move to this track
1522 * - else move up one lane
1524 TimeAxisView::Children kids = (*t)->get_child_list();
1525 TimeAxisView::Children::iterator pkid = kids.end();
1527 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1528 if ((*ci)->hidden()) {
1532 std::pair<TimeAxisView*,double> dev;
1533 dev = (*ci)->covers_y_position (top_of_trackviews);
1535 /* some automation lane is currently at the top */
1536 if (ci == kids.begin()) {
1537 /* first (top-most) autmation lane is at the top.
1538 * jump directly to this track's top
1540 ensure_time_axis_view_is_visible (**t, true);
1543 else if (pkid != kids.end()) {
1544 /* some other automation lane is at the top.
1545 * move up to prev automation lane.
1547 ensure_time_axis_view_is_visible (**pkid, true);
1550 assert(0); // not reached
1561 if (prev != track_views.end()) {
1562 // move to bottom-most automation-lane of the previous track
1563 TimeAxisView::Children kids = (*prev)->get_child_list();
1564 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1565 if (!skip_child_views) {
1566 // find the last visible lane
1567 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1568 if (!(*ci)->hidden()) {
1574 if (pkid != kids.rend()) {
1575 ensure_time_axis_view_is_visible (**pkid, true);
1577 ensure_time_axis_view_is_visible (**prev, true);
1586 Editor::scroll_left_step ()
1588 framepos_t xdelta = (current_page_samples() / 8);
1590 if (leftmost_frame > xdelta) {
1591 reset_x_origin (leftmost_frame - xdelta);
1599 Editor::scroll_right_step ()
1601 framepos_t xdelta = (current_page_samples() / 8);
1603 if (max_framepos - xdelta > leftmost_frame) {
1604 reset_x_origin (leftmost_frame + xdelta);
1606 reset_x_origin (max_framepos - current_page_samples());
1611 Editor::scroll_left_half_page ()
1613 framepos_t xdelta = (current_page_samples() / 2);
1614 if (leftmost_frame > xdelta) {
1615 reset_x_origin (leftmost_frame - xdelta);
1622 Editor::scroll_right_half_page ()
1624 framepos_t xdelta = (current_page_samples() / 2);
1625 if (max_framepos - xdelta > leftmost_frame) {
1626 reset_x_origin (leftmost_frame + xdelta);
1628 reset_x_origin (max_framepos - current_page_samples());
1635 Editor::tav_zoom_step (bool coarser)
1637 DisplaySuspender ds;
1641 if (selection->tracks.empty()) {
1644 ts = &selection->tracks;
1647 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1648 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1649 tv->step_height (coarser);
1654 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1656 DisplaySuspender ds;
1660 if (selection->tracks.empty() || force_all) {
1663 ts = &selection->tracks;
1666 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1667 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1668 uint32_t h = tv->current_height ();
1673 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1678 tv->set_height (h + 5);
1684 Editor::temporal_zoom_step_mouse_focus (bool coarser)
1686 Editing::ZoomFocus temp_focus = zoom_focus;
1687 zoom_focus = Editing::ZoomFocusMouse;
1688 temporal_zoom_step (coarser);
1689 zoom_focus = temp_focus;
1693 Editor::temporal_zoom_step (bool coarser)
1695 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1697 framecnt_t nspp = samples_per_pixel;
1705 temporal_zoom (nspp);
1709 Editor::temporal_zoom (framecnt_t fpp)
1715 framepos_t current_page = current_page_samples();
1716 framepos_t current_leftmost = leftmost_frame;
1717 framepos_t current_rightmost;
1718 framepos_t current_center;
1719 framepos_t new_page_size;
1720 framepos_t half_page_size;
1721 framepos_t leftmost_after_zoom = 0;
1723 bool in_track_canvas;
1727 if (fpp == samples_per_pixel) {
1731 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1732 // segfaults for lack of memory. If somebody decides this is not high enough I
1733 // believe it can be raisen to higher values but some limit must be in place.
1735 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1736 // all of which is used for the editor track displays. The whole day
1737 // would be 4147200000 samples, so 2592000 samples per pixel.
1739 nfpp = min (fpp, (framecnt_t) 2592000);
1740 nfpp = max ((framecnt_t) 1, nfpp);
1742 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1743 half_page_size = new_page_size / 2;
1745 switch (zoom_focus) {
1747 leftmost_after_zoom = current_leftmost;
1750 case ZoomFocusRight:
1751 current_rightmost = leftmost_frame + current_page;
1752 if (current_rightmost < new_page_size) {
1753 leftmost_after_zoom = 0;
1755 leftmost_after_zoom = current_rightmost - new_page_size;
1759 case ZoomFocusCenter:
1760 current_center = current_leftmost + (current_page/2);
1761 if (current_center < half_page_size) {
1762 leftmost_after_zoom = 0;
1764 leftmost_after_zoom = current_center - half_page_size;
1768 case ZoomFocusPlayhead:
1769 /* centre playhead */
1770 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1773 leftmost_after_zoom = 0;
1774 } else if (l > max_framepos) {
1775 leftmost_after_zoom = max_framepos - new_page_size;
1777 leftmost_after_zoom = (framepos_t) l;
1781 case ZoomFocusMouse:
1782 /* try to keep the mouse over the same point in the display */
1784 if (!mouse_frame (where, in_track_canvas)) {
1785 /* use playhead instead */
1786 where = playhead_cursor->current_frame ();
1788 if (where < half_page_size) {
1789 leftmost_after_zoom = 0;
1791 leftmost_after_zoom = where - half_page_size;
1796 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1799 leftmost_after_zoom = 0;
1800 } else if (l > max_framepos) {
1801 leftmost_after_zoom = max_framepos - new_page_size;
1803 leftmost_after_zoom = (framepos_t) l;
1810 /* try to keep the edit point in the same place */
1811 where = get_preferred_edit_position ();
1815 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1818 leftmost_after_zoom = 0;
1819 } else if (l > max_framepos) {
1820 leftmost_after_zoom = max_framepos - new_page_size;
1822 leftmost_after_zoom = (framepos_t) l;
1826 /* edit point not defined */
1833 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1835 reposition_and_zoom (leftmost_after_zoom, nfpp);
1839 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1841 /* this func helps make sure we leave a little space
1842 at each end of the editor so that the zoom doesn't fit the region
1843 precisely to the screen.
1846 GdkScreen* screen = gdk_screen_get_default ();
1847 const gint pixwidth = gdk_screen_get_width (screen);
1848 const gint mmwidth = gdk_screen_get_width_mm (screen);
1849 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1850 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1852 const framepos_t range = end - start;
1853 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1854 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1856 if (start > extra_samples) {
1857 start -= extra_samples;
1862 if (max_framepos - extra_samples > end) {
1863 end += extra_samples;
1870 Editor::temporal_zoom_region (bool both_axes)
1872 framepos_t start = max_framepos;
1874 set<TimeAxisView*> tracks;
1876 if ( !get_selection_extents(start, end) )
1879 calc_extra_zoom_edges (start, end);
1881 /* if we're zooming on both axes we need to save track heights etc.
1884 undo_visual_stack.push_back (current_visual_state (both_axes));
1886 PBD::Unwinder<bool> nsv (no_save_visual, true);
1888 temporal_zoom_by_frame (start, end);
1891 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1893 /* set visible track heights appropriately */
1895 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1896 (*t)->set_height (per_track_height);
1899 /* hide irrelevant tracks */
1901 DisplaySuspender ds;
1903 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1904 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1905 hide_track_in_display (*i);
1909 vertical_adjustment.set_value (0.0);
1912 redo_visual_stack.push_back (current_visual_state (both_axes));
1917 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1919 start = max_framepos;
1923 //ToDo: if notes are selected, set extents to that selection
1925 //ToDo: if control points are selected, set extents to that selection
1927 if ( !selection->regions.empty() ) {
1928 RegionSelection rs = get_regions_from_selection_and_entered ();
1930 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1932 if ((*i)->region()->position() < start) {
1933 start = (*i)->region()->position();
1936 if ((*i)->region()->last_frame() + 1 > end) {
1937 end = (*i)->region()->last_frame() + 1;
1941 } else if (!selection->time.empty()) {
1942 start = selection->time.start();
1943 end = selection->time.end_frame();
1945 ret = false; //no selection found
1948 if ((start == 0 && end == 0) || end < start) {
1957 Editor::temporal_zoom_selection (bool both_axes)
1959 if (!selection) return;
1961 //ToDo: if notes are selected, zoom to that
1963 //ToDo: if control points are selected, zoom to that
1965 //if region(s) are selected, zoom to that
1966 if ( !selection->regions.empty() )
1967 temporal_zoom_region (both_axes);
1969 //if a range is selected, zoom to that
1970 if (!selection->time.empty()) {
1972 framepos_t start, end;
1973 if (get_selection_extents (start, end)) {
1974 calc_extra_zoom_edges(start, end);
1975 temporal_zoom_by_frame (start, end);
1985 Editor::temporal_zoom_session ()
1987 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1990 framecnt_t start = _session->current_start_frame();
1991 framecnt_t end = _session->current_end_frame();
1993 if (_session->actively_recording () ) {
1994 framepos_t cur = playhead_cursor->current_frame ();
1996 /* recording beyond the end marker; zoom out
1997 * by 5 seconds more so that if 'follow
1998 * playhead' is active we don't immediately
2001 end = cur + _session->frame_rate() * 5;
2005 if ((start == 0 && end == 0) || end < start) {
2009 calc_extra_zoom_edges(start, end);
2011 temporal_zoom_by_frame (start, end);
2016 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2018 if (!_session) return;
2020 if ((start == 0 && end == 0) || end < start) {
2024 framepos_t range = end - start;
2026 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2028 framepos_t new_page = range;
2029 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2030 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2032 if (new_leftmost > middle) {
2036 if (new_leftmost < 0) {
2040 reposition_and_zoom (new_leftmost, new_fpp);
2044 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2050 framecnt_t range_before = frame - leftmost_frame;
2054 if (samples_per_pixel <= 1) {
2057 new_spp = samples_per_pixel + (samples_per_pixel/2);
2059 range_before += range_before/2;
2061 if (samples_per_pixel >= 1) {
2062 new_spp = samples_per_pixel - (samples_per_pixel/2);
2064 /* could bail out here since we cannot zoom any finer,
2065 but leave that to the equality test below
2067 new_spp = samples_per_pixel;
2070 range_before -= range_before/2;
2073 if (new_spp == samples_per_pixel) {
2077 /* zoom focus is automatically taken as @param frame when this
2081 framepos_t new_leftmost = frame - (framepos_t)range_before;
2083 if (new_leftmost > frame) {
2087 if (new_leftmost < 0) {
2091 reposition_and_zoom (new_leftmost, new_spp);
2096 Editor::choose_new_marker_name(string &name) {
2098 if (!UIConfiguration::instance().get_name_new_markers()) {
2099 /* don't prompt user for a new name */
2103 ArdourPrompter dialog (true);
2105 dialog.set_prompt (_("New Name:"));
2107 dialog.set_title (_("New Location Marker"));
2109 dialog.set_name ("MarkNameWindow");
2110 dialog.set_size_request (250, -1);
2111 dialog.set_position (Gtk::WIN_POS_MOUSE);
2113 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2114 dialog.set_initial_text (name);
2118 switch (dialog.run ()) {
2119 case RESPONSE_ACCEPT:
2125 dialog.get_result(name);
2132 Editor::add_location_from_selection ()
2136 if (selection->time.empty()) {
2140 if (_session == 0 || clicked_axisview == 0) {
2144 framepos_t start = selection->time[clicked_selection].start;
2145 framepos_t end = selection->time[clicked_selection].end;
2147 _session->locations()->next_available_name(rangename,"selection");
2148 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2150 begin_reversible_command (_("add marker"));
2152 XMLNode &before = _session->locations()->get_state();
2153 _session->locations()->add (location, true);
2154 XMLNode &after = _session->locations()->get_state();
2155 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2157 commit_reversible_command ();
2161 Editor::add_location_mark (framepos_t where)
2165 select_new_marker = true;
2167 _session->locations()->next_available_name(markername,"mark");
2168 if (!choose_new_marker_name(markername)) {
2171 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2172 begin_reversible_command (_("add marker"));
2174 XMLNode &before = _session->locations()->get_state();
2175 _session->locations()->add (location, true);
2176 XMLNode &after = _session->locations()->get_state();
2177 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2179 commit_reversible_command ();
2183 Editor::set_session_start_from_playhead ()
2189 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2190 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2192 XMLNode &before = loc->get_state();
2194 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2196 XMLNode &after = loc->get_state();
2198 begin_reversible_command (_("Set session start"));
2200 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2202 commit_reversible_command ();
2207 Editor::set_session_end_from_playhead ()
2213 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2214 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2216 XMLNode &before = loc->get_state();
2218 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2220 XMLNode &after = loc->get_state();
2222 begin_reversible_command (_("Set session start"));
2224 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2226 commit_reversible_command ();
2231 Editor::add_location_from_playhead_cursor ()
2233 add_location_mark (_session->audible_frame());
2237 Editor::remove_location_at_playhead_cursor ()
2241 XMLNode &before = _session->locations()->get_state();
2242 bool removed = false;
2244 //find location(s) at this time
2245 Locations::LocationList locs;
2246 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2247 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2248 if ((*i)->is_mark()) {
2249 _session->locations()->remove (*i);
2256 begin_reversible_command (_("remove marker"));
2257 XMLNode &after = _session->locations()->get_state();
2258 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2259 commit_reversible_command ();
2264 /** Add a range marker around each selected region */
2266 Editor::add_locations_from_region ()
2268 RegionSelection rs = get_regions_from_selection_and_entered ();
2273 bool commit = false;
2275 XMLNode &before = _session->locations()->get_state();
2277 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2279 boost::shared_ptr<Region> region = (*i)->region ();
2281 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2283 _session->locations()->add (location, true);
2288 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2289 XMLNode &after = _session->locations()->get_state();
2290 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2291 commit_reversible_command ();
2295 /** Add a single range marker around all selected regions */
2297 Editor::add_location_from_region ()
2299 RegionSelection rs = get_regions_from_selection_and_entered ();
2305 XMLNode &before = _session->locations()->get_state();
2309 if (rs.size() > 1) {
2310 _session->locations()->next_available_name(markername, "regions");
2312 RegionView* rv = *(rs.begin());
2313 boost::shared_ptr<Region> region = rv->region();
2314 markername = region->name();
2317 if (!choose_new_marker_name(markername)) {
2321 // single range spanning all selected
2322 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2323 _session->locations()->add (location, true);
2325 begin_reversible_command (_("add marker"));
2326 XMLNode &after = _session->locations()->get_state();
2327 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2328 commit_reversible_command ();
2334 Editor::jump_forward_to_mark ()
2340 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2346 _session->request_locate (pos, _session->transport_rolling());
2350 Editor::jump_backward_to_mark ()
2356 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2362 _session->request_locate (pos, _session->transport_rolling());
2368 framepos_t const pos = _session->audible_frame ();
2371 _session->locations()->next_available_name (markername, "mark");
2373 if (!choose_new_marker_name (markername)) {
2377 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2381 Editor::clear_markers ()
2384 begin_reversible_command (_("clear markers"));
2386 XMLNode &before = _session->locations()->get_state();
2387 _session->locations()->clear_markers ();
2388 XMLNode &after = _session->locations()->get_state();
2389 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2391 commit_reversible_command ();
2396 Editor::clear_ranges ()
2399 begin_reversible_command (_("clear ranges"));
2401 XMLNode &before = _session->locations()->get_state();
2403 _session->locations()->clear_ranges ();
2405 XMLNode &after = _session->locations()->get_state();
2406 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2408 commit_reversible_command ();
2413 Editor::clear_locations ()
2415 begin_reversible_command (_("clear locations"));
2417 XMLNode &before = _session->locations()->get_state();
2418 _session->locations()->clear ();
2419 XMLNode &after = _session->locations()->get_state();
2420 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2422 commit_reversible_command ();
2426 Editor::unhide_markers ()
2428 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2429 Location *l = (*i).first;
2430 if (l->is_hidden() && l->is_mark()) {
2431 l->set_hidden(false, this);
2437 Editor::unhide_ranges ()
2439 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2440 Location *l = (*i).first;
2441 if (l->is_hidden() && l->is_range_marker()) {
2442 l->set_hidden(false, this);
2447 /* INSERT/REPLACE */
2450 Editor::insert_region_list_selection (float times)
2452 RouteTimeAxisView *tv = 0;
2453 boost::shared_ptr<Playlist> playlist;
2455 if (clicked_routeview != 0) {
2456 tv = clicked_routeview;
2457 } else if (!selection->tracks.empty()) {
2458 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2461 } else if (entered_track != 0) {
2462 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2469 if ((playlist = tv->playlist()) == 0) {
2473 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2478 begin_reversible_command (_("insert region"));
2479 playlist->clear_changes ();
2480 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2481 if (Config->get_edit_mode() == Ripple)
2482 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2484 _session->add_command(new StatefulDiffCommand (playlist));
2485 commit_reversible_command ();
2488 /* BUILT-IN EFFECTS */
2491 Editor::reverse_selection ()
2496 /* GAIN ENVELOPE EDITING */
2499 Editor::edit_envelope ()
2506 Editor::transition_to_rolling (bool fwd)
2512 if (_session->config.get_external_sync()) {
2513 switch (Config->get_sync_source()) {
2517 /* transport controlled by the master */
2522 if (_session->is_auditioning()) {
2523 _session->cancel_audition ();
2527 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2531 Editor::play_from_start ()
2533 _session->request_locate (_session->current_start_frame(), true);
2537 Editor::play_from_edit_point ()
2539 _session->request_locate (get_preferred_edit_position(), true);
2543 Editor::play_from_edit_point_and_return ()
2545 framepos_t start_frame;
2546 framepos_t return_frame;
2548 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2550 if (_session->transport_rolling()) {
2551 _session->request_locate (start_frame, false);
2555 /* don't reset the return frame if its already set */
2557 if ((return_frame = _session->requested_return_frame()) < 0) {
2558 return_frame = _session->audible_frame();
2561 if (start_frame >= 0) {
2562 _session->request_roll_at_and_return (start_frame, return_frame);
2567 Editor::play_selection ()
2569 framepos_t start, end;
2570 if (!get_selection_extents ( start, end))
2573 AudioRange ar (start, end, 0);
2574 list<AudioRange> lar;
2577 _session->request_play_range (&lar, true);
2581 Editor::get_preroll ()
2583 return Config->get_preroll_seconds() * _session->frame_rate();
2588 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2590 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2593 location -= get_preroll();
2595 //don't try to locate before the beginning of time
2599 //if follow_playhead is on, keep the playhead on the screen
2600 if ( _follow_playhead )
2601 if ( location < leftmost_frame )
2602 location = leftmost_frame;
2604 _session->request_locate( location );
2608 Editor::play_with_preroll ()
2611 framepos_t preroll = get_preroll();
2613 framepos_t start, end;
2614 if (!get_selection_extents ( start, end))
2617 if (start > preroll)
2618 start = start - preroll;
2620 end = end + preroll; //"post-roll"
2622 AudioRange ar (start, end, 0);
2623 list<AudioRange> lar;
2626 _session->request_play_range (&lar, true);
2631 Editor::play_location (Location& location)
2633 if (location.start() <= location.end()) {
2637 _session->request_bounded_roll (location.start(), location.end());
2641 Editor::loop_location (Location& location)
2643 if (location.start() <= location.end()) {
2649 if ((tll = transport_loop_location()) != 0) {
2650 tll->set (location.start(), location.end());
2652 // enable looping, reposition and start rolling
2653 _session->request_locate (tll->start(), true);
2654 _session->request_play_loop (true);
2659 Editor::do_layer_operation (LayerOperation op)
2661 if (selection->regions.empty ()) {
2665 bool const multiple = selection->regions.size() > 1;
2669 begin_reversible_command (_("raise regions"));
2671 begin_reversible_command (_("raise region"));
2677 begin_reversible_command (_("raise regions to top"));
2679 begin_reversible_command (_("raise region to top"));
2685 begin_reversible_command (_("lower regions"));
2687 begin_reversible_command (_("lower region"));
2693 begin_reversible_command (_("lower regions to bottom"));
2695 begin_reversible_command (_("lower region"));
2700 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2701 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2702 (*i)->clear_owned_changes ();
2705 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2706 boost::shared_ptr<Region> r = (*i)->region ();
2718 r->lower_to_bottom ();
2722 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2723 vector<Command*> cmds;
2725 _session->add_commands (cmds);
2728 commit_reversible_command ();
2732 Editor::raise_region ()
2734 do_layer_operation (Raise);
2738 Editor::raise_region_to_top ()
2740 do_layer_operation (RaiseToTop);
2744 Editor::lower_region ()
2746 do_layer_operation (Lower);
2750 Editor::lower_region_to_bottom ()
2752 do_layer_operation (LowerToBottom);
2755 /** Show the region editor for the selected regions */
2757 Editor::show_region_properties ()
2759 selection->foreach_regionview (&RegionView::show_region_editor);
2762 /** Show the midi list editor for the selected MIDI regions */
2764 Editor::show_midi_list_editor ()
2766 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2770 Editor::rename_region ()
2772 RegionSelection rs = get_regions_from_selection_and_entered ();
2778 ArdourDialog d (_("Rename Region"), true, false);
2780 Label label (_("New name:"));
2783 hbox.set_spacing (6);
2784 hbox.pack_start (label, false, false);
2785 hbox.pack_start (entry, true, true);
2787 d.get_vbox()->set_border_width (12);
2788 d.get_vbox()->pack_start (hbox, false, false);
2790 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2791 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2793 d.set_size_request (300, -1);
2795 entry.set_text (rs.front()->region()->name());
2796 entry.select_region (0, -1);
2798 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2804 int const ret = d.run();
2808 if (ret != RESPONSE_OK) {
2812 std::string str = entry.get_text();
2813 strip_whitespace_edges (str);
2815 rs.front()->region()->set_name (str);
2816 _regions->redisplay ();
2820 /** Start an audition of the first selected region */
2822 Editor::play_edit_range ()
2824 framepos_t start, end;
2826 if (get_edit_op_range (start, end)) {
2827 _session->request_bounded_roll (start, end);
2832 Editor::play_selected_region ()
2834 framepos_t start = max_framepos;
2837 RegionSelection rs = get_regions_from_selection_and_entered ();
2843 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2844 if ((*i)->region()->position() < start) {
2845 start = (*i)->region()->position();
2847 if ((*i)->region()->last_frame() + 1 > end) {
2848 end = (*i)->region()->last_frame() + 1;
2852 _session->request_bounded_roll (start, end);
2856 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2858 _session->audition_region (region);
2862 Editor::region_from_selection ()
2864 if (clicked_axisview == 0) {
2868 if (selection->time.empty()) {
2872 framepos_t start = selection->time[clicked_selection].start;
2873 framepos_t end = selection->time[clicked_selection].end;
2875 TrackViewList tracks = get_tracks_for_range_action ();
2877 framepos_t selection_cnt = end - start + 1;
2879 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2880 boost::shared_ptr<Region> current;
2881 boost::shared_ptr<Playlist> pl;
2882 framepos_t internal_start;
2885 if ((pl = (*i)->playlist()) == 0) {
2889 if ((current = pl->top_region_at (start)) == 0) {
2893 internal_start = start - current->position();
2894 RegionFactory::region_name (new_name, current->name(), true);
2898 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2899 plist.add (ARDOUR::Properties::length, selection_cnt);
2900 plist.add (ARDOUR::Properties::name, new_name);
2901 plist.add (ARDOUR::Properties::layer, 0);
2903 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2908 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2910 if (selection->time.empty() || selection->tracks.empty()) {
2914 framepos_t start, end;
2915 if (clicked_selection) {
2916 start = selection->time[clicked_selection].start;
2917 end = selection->time[clicked_selection].end;
2919 start = selection->time.start();
2920 end = selection->time.end_frame();
2923 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2924 sort_track_selection (ts);
2926 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2927 boost::shared_ptr<Region> current;
2928 boost::shared_ptr<Playlist> playlist;
2929 framepos_t internal_start;
2932 if ((playlist = (*i)->playlist()) == 0) {
2936 if ((current = playlist->top_region_at(start)) == 0) {
2940 internal_start = start - current->position();
2941 RegionFactory::region_name (new_name, current->name(), true);
2945 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2946 plist.add (ARDOUR::Properties::length, end - start + 1);
2947 plist.add (ARDOUR::Properties::name, new_name);
2949 new_regions.push_back (RegionFactory::create (current, plist));
2954 Editor::split_multichannel_region ()
2956 RegionSelection rs = get_regions_from_selection_and_entered ();
2962 vector< boost::shared_ptr<Region> > v;
2964 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2965 (*x)->region()->separate_by_channel (*_session, v);
2970 Editor::new_region_from_selection ()
2972 region_from_selection ();
2973 cancel_selection ();
2977 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2979 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2980 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2981 case Evoral::OverlapNone:
2989 * - selected tracks, or if there are none...
2990 * - tracks containing selected regions, or if there are none...
2995 Editor::get_tracks_for_range_action () const
2999 if (selection->tracks.empty()) {
3001 /* use tracks with selected regions */
3003 RegionSelection rs = selection->regions;
3005 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3006 TimeAxisView* tv = &(*i)->get_time_axis_view();
3008 if (!t.contains (tv)) {
3014 /* no regions and no tracks: use all tracks */
3020 t = selection->tracks;
3023 return t.filter_to_unique_playlists();
3027 Editor::separate_regions_between (const TimeSelection& ts)
3029 bool in_command = false;
3030 boost::shared_ptr<Playlist> playlist;
3031 RegionSelection new_selection;
3033 TrackViewList tmptracks = get_tracks_for_range_action ();
3034 sort_track_selection (tmptracks);
3036 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3038 RouteTimeAxisView* rtv;
3040 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3042 if (rtv->is_track()) {
3044 /* no edits to destructive tracks */
3046 if (rtv->track()->destructive()) {
3050 if ((playlist = rtv->playlist()) != 0) {
3052 playlist->clear_changes ();
3054 /* XXX need to consider musical time selections here at some point */
3056 double speed = rtv->track()->speed();
3059 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3061 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3062 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3064 latest_regionviews.clear ();
3066 playlist->partition ((framepos_t)((*t).start * speed),
3067 (framepos_t)((*t).end * speed), false);
3071 if (!latest_regionviews.empty()) {
3073 rtv->view()->foreach_regionview (sigc::bind (
3074 sigc::ptr_fun (add_if_covered),
3075 &(*t), &new_selection));
3078 begin_reversible_command (_("separate"));
3082 /* pick up changes to existing regions */
3084 vector<Command*> cmds;
3085 playlist->rdiff (cmds);
3086 _session->add_commands (cmds);
3088 /* pick up changes to the playlist itself (adds/removes)
3091 _session->add_command(new StatefulDiffCommand (playlist));
3100 // selection->set (new_selection);
3102 commit_reversible_command ();
3106 struct PlaylistState {
3107 boost::shared_ptr<Playlist> playlist;
3111 /** Take tracks from get_tracks_for_range_action and cut any regions
3112 * on those tracks so that the tracks are empty over the time
3116 Editor::separate_region_from_selection ()
3118 /* preferentially use *all* ranges in the time selection if we're in range mode
3119 to allow discontiguous operation, since get_edit_op_range() currently
3120 returns a single range.
3123 if (!selection->time.empty()) {
3125 separate_regions_between (selection->time);
3132 if (get_edit_op_range (start, end)) {
3134 AudioRange ar (start, end, 1);
3138 separate_regions_between (ts);
3144 Editor::separate_region_from_punch ()
3146 Location* loc = _session->locations()->auto_punch_location();
3148 separate_regions_using_location (*loc);
3153 Editor::separate_region_from_loop ()
3155 Location* loc = _session->locations()->auto_loop_location();
3157 separate_regions_using_location (*loc);
3162 Editor::separate_regions_using_location (Location& loc)
3164 if (loc.is_mark()) {
3168 AudioRange ar (loc.start(), loc.end(), 1);
3173 separate_regions_between (ts);
3176 /** Separate regions under the selected region */
3178 Editor::separate_under_selected_regions ()
3180 vector<PlaylistState> playlists;
3184 rs = get_regions_from_selection_and_entered();
3186 if (!_session || rs.empty()) {
3190 begin_reversible_command (_("separate region under"));
3192 list<boost::shared_ptr<Region> > regions_to_remove;
3194 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3195 // we can't just remove the region(s) in this loop because
3196 // this removes them from the RegionSelection, and they thus
3197 // disappear from underneath the iterator, and the ++i above
3198 // SEGVs in a puzzling fashion.
3200 // so, first iterate over the regions to be removed from rs and
3201 // add them to the regions_to_remove list, and then
3202 // iterate over the list to actually remove them.
3204 regions_to_remove.push_back ((*i)->region());
3207 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3209 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3212 // is this check necessary?
3216 vector<PlaylistState>::iterator i;
3218 //only take state if this is a new playlist.
3219 for (i = playlists.begin(); i != playlists.end(); ++i) {
3220 if ((*i).playlist == playlist) {
3225 if (i == playlists.end()) {
3227 PlaylistState before;
3228 before.playlist = playlist;
3229 before.before = &playlist->get_state();
3231 playlist->freeze ();
3232 playlists.push_back(before);
3235 //Partition on the region bounds
3236 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3238 //Re-add region that was just removed due to the partition operation
3239 playlist->add_region( (*rl), (*rl)->first_frame() );
3242 vector<PlaylistState>::iterator pl;
3244 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3245 (*pl).playlist->thaw ();
3246 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3249 commit_reversible_command ();
3253 Editor::crop_region_to_selection ()
3255 if (!selection->time.empty()) {
3257 crop_region_to (selection->time.start(), selection->time.end_frame());
3264 if (get_edit_op_range (start, end)) {
3265 crop_region_to (start, end);
3272 Editor::crop_region_to (framepos_t start, framepos_t end)
3274 vector<boost::shared_ptr<Playlist> > playlists;
3275 boost::shared_ptr<Playlist> playlist;
3278 if (selection->tracks.empty()) {
3279 ts = track_views.filter_to_unique_playlists();
3281 ts = selection->tracks.filter_to_unique_playlists ();
3284 sort_track_selection (ts);
3286 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3288 RouteTimeAxisView* rtv;
3290 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3292 boost::shared_ptr<Track> t = rtv->track();
3294 if (t != 0 && ! t->destructive()) {
3296 if ((playlist = rtv->playlist()) != 0) {
3297 playlists.push_back (playlist);
3303 if (playlists.empty()) {
3308 framepos_t new_start;
3310 framecnt_t new_length;
3311 bool in_command = false;
3313 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3315 /* Only the top regions at start and end have to be cropped */
3316 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3317 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3319 vector<boost::shared_ptr<Region> > regions;
3321 if (region_at_start != 0) {
3322 regions.push_back (region_at_start);
3324 if (region_at_end != 0) {
3325 regions.push_back (region_at_end);
3328 /* now adjust lengths */
3329 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3331 pos = (*i)->position();
3332 new_start = max (start, pos);
3333 if (max_framepos - pos > (*i)->length()) {
3334 new_end = pos + (*i)->length() - 1;
3336 new_end = max_framepos;
3338 new_end = min (end, new_end);
3339 new_length = new_end - new_start + 1;
3342 begin_reversible_command (_("trim to selection"));
3345 (*i)->clear_changes ();
3346 (*i)->trim_to (new_start, new_length);
3347 _session->add_command (new StatefulDiffCommand (*i));
3352 commit_reversible_command ();
3357 Editor::region_fill_track ()
3359 boost::shared_ptr<Playlist> playlist;
3360 RegionSelection regions = get_regions_from_selection_and_entered ();
3361 RegionSelection foo;
3363 framepos_t const end = _session->current_end_frame ();
3365 if (regions.empty () || regions.end_frame () + 1 >= end) {
3369 framepos_t const start_frame = regions.start ();
3370 framepos_t const end_frame = regions.end_frame ();
3371 framecnt_t const gap = end_frame - start_frame + 1;
3373 begin_reversible_command (Operations::region_fill);
3375 selection->clear_regions ();
3377 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3379 boost::shared_ptr<Region> r ((*i)->region());
3381 TimeAxisView& tv = (*i)->get_time_axis_view();
3382 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3383 latest_regionviews.clear ();
3384 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3386 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3387 playlist = (*i)->region()->playlist();
3388 playlist->clear_changes ();
3389 playlist->duplicate_until (r, position, gap, end);
3390 _session->add_command(new StatefulDiffCommand (playlist));
3394 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3398 selection->set (foo);
3401 commit_reversible_command ();
3405 Editor::set_region_sync_position ()
3407 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3411 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3413 bool in_command = false;
3415 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3417 if (!(*r)->region()->covers (where)) {
3421 boost::shared_ptr<Region> region ((*r)->region());
3424 begin_reversible_command (_("set sync point"));
3428 region->clear_changes ();
3429 region->set_sync_position (where);
3430 _session->add_command(new StatefulDiffCommand (region));
3434 commit_reversible_command ();
3438 /** Remove the sync positions of the selection */
3440 Editor::remove_region_sync ()
3442 RegionSelection rs = get_regions_from_selection_and_entered ();
3448 begin_reversible_command (_("remove region sync"));
3450 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3452 (*i)->region()->clear_changes ();
3453 (*i)->region()->clear_sync_position ();
3454 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3457 commit_reversible_command ();
3461 Editor::naturalize_region ()
3463 RegionSelection rs = get_regions_from_selection_and_entered ();
3469 if (rs.size() > 1) {
3470 begin_reversible_command (_("move regions to original position"));
3472 begin_reversible_command (_("move region to original position"));
3475 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3476 (*i)->region()->clear_changes ();
3477 (*i)->region()->move_to_natural_position ();
3478 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3481 commit_reversible_command ();
3485 Editor::align_regions (RegionPoint what)
3487 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3493 begin_reversible_command (_("align selection"));
3495 framepos_t const position = get_preferred_edit_position ();
3497 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3498 align_region_internal ((*i)->region(), what, position);
3501 commit_reversible_command ();
3504 struct RegionSortByTime {
3505 bool operator() (const RegionView* a, const RegionView* b) {
3506 return a->region()->position() < b->region()->position();
3511 Editor::align_regions_relative (RegionPoint point)
3513 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3519 framepos_t const position = get_preferred_edit_position ();
3521 framepos_t distance = 0;
3525 list<RegionView*> sorted;
3526 rs.by_position (sorted);
3528 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3533 if (position > r->position()) {
3534 distance = position - r->position();
3536 distance = r->position() - position;
3542 if (position > r->last_frame()) {
3543 distance = position - r->last_frame();
3544 pos = r->position() + distance;
3546 distance = r->last_frame() - position;
3547 pos = r->position() - distance;
3553 pos = r->adjust_to_sync (position);
3554 if (pos > r->position()) {
3555 distance = pos - r->position();
3557 distance = r->position() - pos;
3563 if (pos == r->position()) {
3567 begin_reversible_command (_("align selection (relative)"));
3569 /* move first one specially */
3571 r->clear_changes ();
3572 r->set_position (pos);
3573 _session->add_command(new StatefulDiffCommand (r));
3575 /* move rest by the same amount */
3579 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3581 boost::shared_ptr<Region> region ((*i)->region());
3583 region->clear_changes ();
3586 region->set_position (region->position() + distance);
3588 region->set_position (region->position() - distance);
3591 _session->add_command(new StatefulDiffCommand (region));
3595 commit_reversible_command ();
3599 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3601 begin_reversible_command (_("align region"));
3602 align_region_internal (region, point, position);
3603 commit_reversible_command ();
3607 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3609 region->clear_changes ();
3613 region->set_position (region->adjust_to_sync (position));
3617 if (position > region->length()) {
3618 region->set_position (position - region->length());
3623 region->set_position (position);
3627 _session->add_command(new StatefulDiffCommand (region));
3631 Editor::trim_region_front ()
3637 Editor::trim_region_back ()
3639 trim_region (false);
3643 Editor::trim_region (bool front)
3645 framepos_t where = get_preferred_edit_position();
3646 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3652 begin_reversible_command (front ? _("trim front") : _("trim back"));
3654 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3655 if (!(*i)->region()->locked()) {
3657 (*i)->region()->clear_changes ();
3660 (*i)->region()->trim_front (where);
3661 maybe_locate_with_edit_preroll ( where );
3663 (*i)->region()->trim_end (where);
3664 maybe_locate_with_edit_preroll ( where );
3667 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3671 commit_reversible_command ();
3674 /** Trim the end of the selected regions to the position of the edit cursor */
3676 Editor::trim_region_to_loop ()
3678 Location* loc = _session->locations()->auto_loop_location();
3682 trim_region_to_location (*loc, _("trim to loop"));
3686 Editor::trim_region_to_punch ()
3688 Location* loc = _session->locations()->auto_punch_location();
3692 trim_region_to_location (*loc, _("trim to punch"));
3696 Editor::trim_region_to_location (const Location& loc, const char* str)
3698 RegionSelection rs = get_regions_from_selection_and_entered ();
3699 bool in_command = false;
3701 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3702 RegionView* rv = (*x);
3704 /* require region to span proposed trim */
3705 switch (rv->region()->coverage (loc.start(), loc.end())) {
3706 case Evoral::OverlapInternal:
3712 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3721 if (tav->track() != 0) {
3722 speed = tav->track()->speed();
3725 start = session_frame_to_track_frame (loc.start(), speed);
3726 end = session_frame_to_track_frame (loc.end(), speed);
3728 rv->region()->clear_changes ();
3729 rv->region()->trim_to (start, (end - start));
3732 begin_reversible_command (str);
3735 _session->add_command(new StatefulDiffCommand (rv->region()));
3739 commit_reversible_command ();
3744 Editor::trim_region_to_previous_region_end ()
3746 return trim_to_region(false);
3750 Editor::trim_region_to_next_region_start ()
3752 return trim_to_region(true);
3756 Editor::trim_to_region(bool forward)
3758 RegionSelection rs = get_regions_from_selection_and_entered ();
3759 bool in_command = false;
3761 boost::shared_ptr<Region> next_region;
3763 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3765 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3771 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3779 if (atav->track() != 0) {
3780 speed = atav->track()->speed();
3784 boost::shared_ptr<Region> region = arv->region();
3785 boost::shared_ptr<Playlist> playlist (region->playlist());
3787 region->clear_changes ();
3791 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3797 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3798 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3802 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3808 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3810 arv->region_changed (ARDOUR::bounds_change);
3814 begin_reversible_command (_("trim to region"));
3817 _session->add_command(new StatefulDiffCommand (region));
3821 commit_reversible_command ();
3826 Editor::unfreeze_route ()
3828 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3832 clicked_routeview->track()->unfreeze ();
3836 Editor::_freeze_thread (void* arg)
3838 return static_cast<Editor*>(arg)->freeze_thread ();
3842 Editor::freeze_thread ()
3844 /* create event pool because we may need to talk to the session */
3845 SessionEvent::create_per_thread_pool ("freeze events", 64);
3846 /* create per-thread buffers for process() tree to use */
3847 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3848 current_interthread_info->done = true;
3853 Editor::freeze_route ()
3859 /* stop transport before we start. this is important */
3861 _session->request_transport_speed (0.0);
3863 /* wait for just a little while, because the above call is asynchronous */
3865 Glib::usleep (250000);
3867 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3871 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3873 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3874 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3876 d.set_title (_("Cannot freeze"));
3881 if (clicked_routeview->track()->has_external_redirects()) {
3882 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"
3883 "Freezing will only process the signal as far as the first send/insert/return."),
3884 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3886 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3887 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3888 d.set_title (_("Freeze Limits"));
3890 int response = d.run ();
3893 case Gtk::RESPONSE_CANCEL:
3900 InterThreadInfo itt;
3901 current_interthread_info = &itt;
3903 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3905 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3907 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3909 while (!itt.done && !itt.cancel) {
3910 gtk_main_iteration ();
3913 pthread_join (itt.thread, 0);
3914 current_interthread_info = 0;
3918 Editor::bounce_range_selection (bool replace, bool enable_processing)
3920 if (selection->time.empty()) {
3924 TrackSelection views = selection->tracks;
3926 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3928 if (enable_processing) {
3930 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3932 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3934 _("You can't perform this operation because the processing of the signal "
3935 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3936 "You can do this without processing, which is a different operation.")
3938 d.set_title (_("Cannot bounce"));
3945 framepos_t start = selection->time[clicked_selection].start;
3946 framepos_t end = selection->time[clicked_selection].end;
3947 framepos_t cnt = end - start + 1;
3948 bool in_command = false;
3950 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3952 RouteTimeAxisView* rtv;
3954 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3958 boost::shared_ptr<Playlist> playlist;
3960 if ((playlist = rtv->playlist()) == 0) {
3964 InterThreadInfo itt;
3966 playlist->clear_changes ();
3967 playlist->clear_owned_changes ();
3969 boost::shared_ptr<Region> r;
3971 if (enable_processing) {
3972 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3974 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3982 list<AudioRange> ranges;
3983 ranges.push_back (AudioRange (start, start+cnt, 0));
3984 playlist->cut (ranges); // discard result
3985 playlist->add_region (r, start);
3989 begin_reversible_command (_("bounce range"));
3992 vector<Command*> cmds;
3993 playlist->rdiff (cmds);
3994 _session->add_commands (cmds);
3996 _session->add_command (new StatefulDiffCommand (playlist));
4000 commit_reversible_command ();
4004 /** Delete selected regions, automation points or a time range */
4008 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4009 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4010 bool deleted = false;
4011 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4012 deleted = current_mixer_strip->delete_processors ();
4018 /** Cut selected regions, automation points or a time range */
4025 /** Copy selected regions, automation points or a time range */
4033 /** @return true if a Cut, Copy or Clear is possible */
4035 Editor::can_cut_copy () const
4037 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4044 /** Cut, copy or clear selected regions, automation points or a time range.
4045 * @param op Operation (Delete, Cut, Copy or Clear)
4048 Editor::cut_copy (CutCopyOp op)
4050 /* only cancel selection if cut/copy is successful.*/
4056 opname = _("delete");
4065 opname = _("clear");
4069 /* if we're deleting something, and the mouse is still pressed,
4070 the thing we started a drag for will be gone when we release
4071 the mouse button(s). avoid this. see part 2 at the end of
4075 if (op == Delete || op == Cut || op == Clear) {
4076 if (_drags->active ()) {
4081 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4082 cut_buffer->clear ();
4084 if (entered_marker) {
4086 /* cut/delete op while pointing at a marker */
4089 Location* loc = find_location_from_marker (entered_marker, ignored);
4091 if (_session && loc) {
4092 entered_marker = NULL;
4093 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4100 switch (mouse_mode) {
4103 begin_reversible_command (opname + ' ' + X_("MIDI"));
4105 commit_reversible_command ();
4111 bool did_edit = false;
4113 if (!selection->regions.empty() || !selection->points.empty()) {
4114 begin_reversible_command (opname + ' ' + _("objects"));
4117 if (!selection->regions.empty()) {
4118 cut_copy_regions (op, selection->regions);
4120 if (op == Cut || op == Delete) {
4121 selection->clear_regions ();
4125 if (!selection->points.empty()) {
4126 cut_copy_points (op);
4128 if (op == Cut || op == Delete) {
4129 selection->clear_points ();
4132 } else if (selection->time.empty()) {
4133 framepos_t start, end;
4134 /* no time selection, see if we can get an edit range
4137 if (get_edit_op_range (start, end)) {
4138 selection->set (start, end);
4140 } else if (!selection->time.empty()) {
4141 begin_reversible_command (opname + ' ' + _("range"));
4144 cut_copy_ranges (op);
4146 if (op == Cut || op == Delete) {
4147 selection->clear_time ();
4152 /* reset repeated paste state */
4155 commit_reversible_command ();
4158 if (op == Delete || op == Cut || op == Clear) {
4163 struct AutomationRecord {
4164 AutomationRecord () : state (0) , line(NULL) {}
4165 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4167 XMLNode* state; ///< state before any operation
4168 const AutomationLine* line; ///< line this came from
4169 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4172 /** Cut, copy or clear selected automation points.
4173 * @param op Operation (Cut, Copy or Clear)
4176 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4178 if (selection->points.empty ()) {
4182 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4183 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4185 /* Keep a record of the AutomationLists that we end up using in this operation */
4186 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4189 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4190 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4191 const AutomationLine& line = (*i)->line();
4192 const boost::shared_ptr<AutomationList> al = line.the_list();
4193 if (lists.find (al) == lists.end ()) {
4194 /* We haven't seen this list yet, so make a record for it. This includes
4195 taking a copy of its current state, in case this is needed for undo later.
4197 lists[al] = AutomationRecord (&al->get_state (), &line);
4201 if (op == Cut || op == Copy) {
4202 /* This operation will involve putting things in the cut buffer, so create an empty
4203 ControlList for each of our source lists to put the cut buffer data in.
4205 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4206 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4209 /* Add all selected points to the relevant copy ControlLists */
4210 framepos_t start = std::numeric_limits<framepos_t>::max();
4211 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4212 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4213 AutomationList::const_iterator j = (*i)->model();
4215 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4217 /* Update earliest MIDI start time in beats */
4218 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4220 /* Update earliest session start time in frames */
4221 start = std::min(start, (*i)->line().session_position(j));
4225 /* Snap start time backwards, so copy/paste is snap aligned. */
4227 if (earliest == Evoral::Beats::max()) {
4228 earliest = Evoral::Beats(); // Weird... don't offset
4230 earliest.round_down_to_beat();
4232 if (start == std::numeric_limits<double>::max()) {
4233 start = 0; // Weird... don't offset
4235 snap_to(start, RoundDownMaybe);
4238 const double line_offset = midi ? earliest.to_double() : start;
4239 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4240 /* Correct this copy list so that it is relative to the earliest
4241 start time, so relative ordering between points is preserved
4242 when copying from several lists and the paste starts at the
4243 earliest copied piece of data. */
4244 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4245 (*j)->when -= line_offset;
4248 /* And add it to the cut buffer */
4249 cut_buffer->add (i->second.copy);
4253 if (op == Delete || op == Cut) {
4254 /* This operation needs to remove things from the main AutomationList, so do that now */
4256 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4257 i->first->freeze ();
4260 /* Remove each selected point from its AutomationList */
4261 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4262 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4263 al->erase ((*i)->model ());
4266 /* Thaw the lists and add undo records for them */
4267 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4268 boost::shared_ptr<AutomationList> al = i->first;
4270 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4275 /** Cut, copy or clear selected automation points.
4276 * @param op Operation (Cut, Copy or Clear)
4279 Editor::cut_copy_midi (CutCopyOp op)
4281 Evoral::Beats earliest = Evoral::Beats::max();
4282 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4283 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4285 if (!mrv->selection().empty()) {
4286 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4288 mrv->cut_copy_clear (op);
4290 /* XXX: not ideal, as there may be more than one track involved in the selection */
4291 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4295 if (!selection->points.empty()) {
4296 cut_copy_points (op, earliest, true);
4297 if (op == Cut || op == Delete) {
4298 selection->clear_points ();
4303 struct lt_playlist {
4304 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4305 return a.playlist < b.playlist;
4309 struct PlaylistMapping {
4311 boost::shared_ptr<Playlist> pl;
4313 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4316 /** Remove `clicked_regionview' */
4318 Editor::remove_clicked_region ()
4320 if (clicked_routeview == 0 || clicked_regionview == 0) {
4324 begin_reversible_command (_("remove region"));
4326 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4328 playlist->clear_changes ();
4329 playlist->clear_owned_changes ();
4330 playlist->remove_region (clicked_regionview->region());
4331 if (Config->get_edit_mode() == Ripple)
4332 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4334 /* We might have removed regions, which alters other regions' layering_index,
4335 so we need to do a recursive diff here.
4337 vector<Command*> cmds;
4338 playlist->rdiff (cmds);
4339 _session->add_commands (cmds);
4341 _session->add_command(new StatefulDiffCommand (playlist));
4342 commit_reversible_command ();
4346 /** Remove the selected regions */
4348 Editor::remove_selected_regions ()
4350 RegionSelection rs = get_regions_from_selection_and_entered ();
4352 if (!_session || rs.empty()) {
4356 list<boost::shared_ptr<Region> > regions_to_remove;
4358 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4359 // we can't just remove the region(s) in this loop because
4360 // this removes them from the RegionSelection, and they thus
4361 // disappear from underneath the iterator, and the ++i above
4362 // SEGVs in a puzzling fashion.
4364 // so, first iterate over the regions to be removed from rs and
4365 // add them to the regions_to_remove list, and then
4366 // iterate over the list to actually remove them.
4368 regions_to_remove.push_back ((*i)->region());
4371 vector<boost::shared_ptr<Playlist> > playlists;
4373 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4375 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4378 // is this check necessary?
4382 /* get_regions_from_selection_and_entered() guarantees that
4383 the playlists involved are unique, so there is no need
4387 playlists.push_back (playlist);
4389 playlist->clear_changes ();
4390 playlist->clear_owned_changes ();
4391 playlist->freeze ();
4392 playlist->remove_region (*rl);
4393 if (Config->get_edit_mode() == Ripple)
4394 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4398 vector<boost::shared_ptr<Playlist> >::iterator pl;
4399 bool in_command = false;
4401 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4404 /* We might have removed regions, which alters other regions' layering_index,
4405 so we need to do a recursive diff here.
4409 begin_reversible_command (_("remove region"));
4412 vector<Command*> cmds;
4413 (*pl)->rdiff (cmds);
4414 _session->add_commands (cmds);
4416 _session->add_command(new StatefulDiffCommand (*pl));
4420 commit_reversible_command ();
4424 /** Cut, copy or clear selected regions.
4425 * @param op Operation (Cut, Copy or Clear)
4428 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4430 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4431 a map when we want ordered access to both elements. i think.
4434 vector<PlaylistMapping> pmap;
4436 framepos_t first_position = max_framepos;
4438 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4439 FreezeList freezelist;
4441 /* get ordering correct before we cut/copy */
4443 rs.sort_by_position_and_track ();
4445 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4447 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4449 if (op == Cut || op == Clear || op == Delete) {
4450 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4453 FreezeList::iterator fl;
4455 // only take state if this is a new playlist.
4456 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4462 if (fl == freezelist.end()) {
4463 pl->clear_changes();
4464 pl->clear_owned_changes ();
4466 freezelist.insert (pl);
4471 TimeAxisView* tv = &(*x)->get_time_axis_view();
4472 vector<PlaylistMapping>::iterator z;
4474 for (z = pmap.begin(); z != pmap.end(); ++z) {
4475 if ((*z).tv == tv) {
4480 if (z == pmap.end()) {
4481 pmap.push_back (PlaylistMapping (tv));
4485 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4487 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4490 /* region not yet associated with a playlist (e.g. unfinished
4497 TimeAxisView& tv = (*x)->get_time_axis_view();
4498 boost::shared_ptr<Playlist> npl;
4499 RegionSelection::iterator tmp;
4506 vector<PlaylistMapping>::iterator z;
4508 for (z = pmap.begin(); z != pmap.end(); ++z) {
4509 if ((*z).tv == &tv) {
4514 assert (z != pmap.end());
4517 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4525 boost::shared_ptr<Region> r = (*x)->region();
4526 boost::shared_ptr<Region> _xx;
4532 pl->remove_region (r);
4533 if (Config->get_edit_mode() == Ripple)
4534 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4538 _xx = RegionFactory::create (r);
4539 npl->add_region (_xx, r->position() - first_position);
4540 pl->remove_region (r);
4541 if (Config->get_edit_mode() == Ripple)
4542 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4546 /* copy region before adding, so we're not putting same object into two different playlists */
4547 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4551 pl->remove_region (r);
4552 if (Config->get_edit_mode() == Ripple)
4553 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4562 list<boost::shared_ptr<Playlist> > foo;
4564 /* the pmap is in the same order as the tracks in which selected regions occurred */
4566 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4569 foo.push_back ((*i).pl);
4574 cut_buffer->set (foo);
4578 _last_cut_copy_source_track = 0;
4580 _last_cut_copy_source_track = pmap.front().tv;
4584 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4587 /* We might have removed regions, which alters other regions' layering_index,
4588 so we need to do a recursive diff here.
4590 vector<Command*> cmds;
4591 (*pl)->rdiff (cmds);
4592 _session->add_commands (cmds);
4594 _session->add_command (new StatefulDiffCommand (*pl));
4599 Editor::cut_copy_ranges (CutCopyOp op)
4601 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4603 /* Sort the track selection now, so that it if is used, the playlists
4604 selected by the calls below to cut_copy_clear are in the order that
4605 their tracks appear in the editor. This makes things like paste
4606 of ranges work properly.
4609 sort_track_selection (ts);
4612 if (!entered_track) {
4615 ts.push_back (entered_track);
4618 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4619 (*i)->cut_copy_clear (*selection, op);
4624 Editor::paste (float times, bool from_context)
4626 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4628 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4632 Editor::mouse_paste ()
4637 if (!mouse_frame (where, ignored)) {
4642 paste_internal (where, 1);
4646 Editor::paste_internal (framepos_t position, float times)
4648 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4650 if (cut_buffer->empty(internal_editing())) {
4654 if (position == max_framepos) {
4655 position = get_preferred_edit_position();
4656 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4659 if (position == last_paste_pos) {
4660 /* repeated paste in the same position */
4663 /* paste in new location, reset repeated paste state */
4665 last_paste_pos = position;
4668 /* get everything in the correct order */
4671 if (!selection->tracks.empty()) {
4672 /* If there is a track selection, paste into exactly those tracks and
4673 only those tracks. This allows the user to be explicit and override
4674 the below "do the reasonable thing" logic. */
4675 ts = selection->tracks.filter_to_unique_playlists ();
4676 sort_track_selection (ts);
4678 /* Figure out which track to base the paste at. */
4679 TimeAxisView* base_track = NULL;
4680 if (_edit_point == Editing::EditAtMouse && entered_track) {
4681 /* With the mouse edit point, paste onto the track under the mouse. */
4682 base_track = entered_track;
4683 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4684 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4685 base_track = &entered_regionview->get_time_axis_view();
4686 } else if (_last_cut_copy_source_track) {
4687 /* Paste to the track that the cut/copy came from (see mantis #333). */
4688 base_track = _last_cut_copy_source_track;
4690 /* This is "impossible" since we've copied... well, do nothing. */
4694 /* Walk up to parent if necessary, so base track is a route. */
4695 while (base_track->get_parent()) {
4696 base_track = base_track->get_parent();
4699 /* Add base track and all tracks below it. The paste logic will select
4700 the appropriate object types from the cut buffer in relative order. */
4701 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4702 if ((*i)->order() >= base_track->order()) {
4707 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4708 sort_track_selection (ts);
4710 /* Add automation children of each track in order, for pasting several lines. */
4711 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4712 /* Add any automation children for pasting several lines */
4713 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4718 typedef RouteTimeAxisView::AutomationTracks ATracks;
4719 const ATracks& atracks = rtv->automation_tracks();
4720 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4721 i = ts.insert(i, a->second.get());
4726 /* We now have a list of trackviews starting at base_track, including
4727 automation children, in the order shown in the editor, e.g. R1,
4728 R1.A1, R1.A2, R2, R2.A1, ... */
4731 begin_reversible_command (Operations::paste);
4733 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4734 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4735 /* Only one line copied, and one automation track selected. Do a
4736 "greedy" paste from one automation type to another. */
4738 PasteContext ctx(paste_count, times, ItemCounts(), true);
4739 ts.front()->paste (position, *cut_buffer, ctx);
4743 /* Paste into tracks */
4745 PasteContext ctx(paste_count, times, ItemCounts(), false);
4746 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4747 (*i)->paste (position, *cut_buffer, ctx);
4751 commit_reversible_command ();
4755 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4757 if (regions.empty ()) {
4761 boost::shared_ptr<Playlist> playlist;
4762 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4763 RegionSelection foo;
4765 framepos_t const start_frame = regions.start ();
4766 framepos_t const end_frame = regions.end_frame ();
4767 framecnt_t const gap = end_frame - start_frame + 1;
4769 begin_reversible_command (Operations::duplicate_region);
4771 selection->clear_regions ();
4773 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4775 boost::shared_ptr<Region> r ((*i)->region());
4777 TimeAxisView& tv = (*i)->get_time_axis_view();
4778 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4779 latest_regionviews.clear ();
4780 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4782 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4783 playlist = (*i)->region()->playlist();
4784 playlist->clear_changes ();
4785 playlist->duplicate (r, position, gap, times);
4786 _session->add_command(new StatefulDiffCommand (playlist));
4790 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4794 selection->set (foo);
4797 commit_reversible_command ();
4801 Editor::duplicate_selection (float times)
4803 if (selection->time.empty() || selection->tracks.empty()) {
4807 boost::shared_ptr<Playlist> playlist;
4809 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4811 bool in_command = false;
4813 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4814 if ((playlist = (*i)->playlist()) == 0) {
4817 playlist->clear_changes ();
4819 if (clicked_selection) {
4820 playlist->duplicate_range (selection->time[clicked_selection], times);
4822 playlist->duplicate_ranges (selection->time, times);
4826 begin_reversible_command (_("duplicate range selection"));
4829 _session->add_command (new StatefulDiffCommand (playlist));
4834 // now "move" range selection to after the current range selection
4835 framecnt_t distance = 0;
4837 if (clicked_selection) {
4838 distance = selection->time[clicked_selection].end -
4839 selection->time[clicked_selection].start;
4841 distance = selection->time.end_frame() - selection->time.start();
4844 selection->move_time (distance);
4846 commit_reversible_command ();
4850 /** Reset all selected points to the relevant default value */
4852 Editor::reset_point_selection ()
4854 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4855 ARDOUR::AutomationList::iterator j = (*i)->model ();
4856 (*j)->value = (*i)->line().the_list()->default_value ();
4861 Editor::center_playhead ()
4863 float const page = _visible_canvas_width * samples_per_pixel;
4864 center_screen_internal (playhead_cursor->current_frame (), page);
4868 Editor::center_edit_point ()
4870 float const page = _visible_canvas_width * samples_per_pixel;
4871 center_screen_internal (get_preferred_edit_position(), page);
4874 /** Caller must begin and commit a reversible command */
4876 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4878 playlist->clear_changes ();
4880 _session->add_command (new StatefulDiffCommand (playlist));
4884 Editor::nudge_track (bool use_edit, bool forwards)
4886 boost::shared_ptr<Playlist> playlist;
4887 framepos_t distance;
4888 framepos_t next_distance;
4892 start = get_preferred_edit_position();
4897 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4901 if (selection->tracks.empty()) {
4905 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4906 bool in_command = false;
4908 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4910 if ((playlist = (*i)->playlist()) == 0) {
4914 playlist->clear_changes ();
4915 playlist->clear_owned_changes ();
4917 playlist->nudge_after (start, distance, forwards);
4920 begin_reversible_command (_("nudge track"));
4923 vector<Command*> cmds;
4925 playlist->rdiff (cmds);
4926 _session->add_commands (cmds);
4928 _session->add_command (new StatefulDiffCommand (playlist));
4932 commit_reversible_command ();
4937 Editor::remove_last_capture ()
4939 vector<string> choices;
4946 if (Config->get_verify_remove_last_capture()) {
4947 prompt = _("Do you really want to destroy the last capture?"
4948 "\n(This is destructive and cannot be undone)");
4950 choices.push_back (_("No, do nothing."));
4951 choices.push_back (_("Yes, destroy it."));
4953 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4955 if (prompter.run () == 1) {
4956 _session->remove_last_capture ();
4957 _regions->redisplay ();
4961 _session->remove_last_capture();
4962 _regions->redisplay ();
4967 Editor::normalize_region ()
4973 RegionSelection rs = get_regions_from_selection_and_entered ();
4979 NormalizeDialog dialog (rs.size() > 1);
4981 if (dialog.run () == RESPONSE_CANCEL) {
4985 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4988 /* XXX: should really only count audio regions here */
4989 int const regions = rs.size ();
4991 /* Make a list of the selected audio regions' maximum amplitudes, and also
4992 obtain the maximum amplitude of them all.
4994 list<double> max_amps;
4996 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4997 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4999 dialog.descend (1.0 / regions);
5000 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5003 /* the user cancelled the operation */
5007 max_amps.push_back (a);
5008 max_amp = max (max_amp, a);
5013 list<double>::const_iterator a = max_amps.begin ();
5014 bool in_command = false;
5016 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5017 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5022 arv->region()->clear_changes ();
5024 double const amp = dialog.normalize_individually() ? *a : max_amp;
5026 arv->audio_region()->normalize (amp, dialog.target ());
5029 begin_reversible_command (_("normalize"));
5032 _session->add_command (new StatefulDiffCommand (arv->region()));
5038 commit_reversible_command ();
5044 Editor::reset_region_scale_amplitude ()
5050 RegionSelection rs = get_regions_from_selection_and_entered ();
5056 bool in_command = false;
5058 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5059 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5062 arv->region()->clear_changes ();
5063 arv->audio_region()->set_scale_amplitude (1.0f);
5066 begin_reversible_command ("reset gain");
5069 _session->add_command (new StatefulDiffCommand (arv->region()));
5073 commit_reversible_command ();
5078 Editor::adjust_region_gain (bool up)
5080 RegionSelection rs = get_regions_from_selection_and_entered ();
5082 if (!_session || rs.empty()) {
5086 bool in_command = false;
5088 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5089 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5094 arv->region()->clear_changes ();
5096 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5104 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5107 begin_reversible_command ("adjust region gain");
5110 _session->add_command (new StatefulDiffCommand (arv->region()));
5114 commit_reversible_command ();
5120 Editor::reverse_region ()
5126 Reverse rev (*_session);
5127 apply_filter (rev, _("reverse regions"));
5131 Editor::strip_region_silence ()
5137 RegionSelection rs = get_regions_from_selection_and_entered ();
5143 std::list<RegionView*> audio_only;
5145 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5146 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5148 audio_only.push_back (arv);
5152 assert (!audio_only.empty());
5154 StripSilenceDialog d (_session, audio_only);
5155 int const r = d.run ();
5159 if (r == Gtk::RESPONSE_OK) {
5160 ARDOUR::AudioIntervalMap silences;
5161 d.silences (silences);
5162 StripSilence s (*_session, silences, d.fade_length());
5164 apply_filter (s, _("strip silence"), &d);
5169 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5171 Evoral::Sequence<Evoral::Beats>::Notes selected;
5172 mrv.selection_as_notelist (selected, true);
5174 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5175 v.push_back (selected);
5177 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5178 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5180 return op (mrv.midi_region()->model(), pos_beats, v);
5184 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5190 bool in_command = false;
5192 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5193 RegionSelection::const_iterator tmp = r;
5196 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5199 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5202 begin_reversible_command (op.name ());
5206 _session->add_command (cmd);
5214 commit_reversible_command ();
5219 Editor::fork_region ()
5221 RegionSelection rs = get_regions_from_selection_and_entered ();
5227 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5228 bool in_command = false;
5232 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5233 RegionSelection::iterator tmp = r;
5236 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5240 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5241 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5242 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5245 begin_reversible_command (_("Fork Region(s)"));
5248 playlist->clear_changes ();
5249 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5250 _session->add_command(new StatefulDiffCommand (playlist));
5252 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5260 commit_reversible_command ();
5265 Editor::quantize_region ()
5268 quantize_regions(get_regions_from_selection_and_entered ());
5273 Editor::quantize_regions (const RegionSelection& rs)
5275 if (rs.n_midi_regions() == 0) {
5279 if (!quantize_dialog) {
5280 quantize_dialog = new QuantizeDialog (*this);
5283 quantize_dialog->present ();
5284 const int r = quantize_dialog->run ();
5285 quantize_dialog->hide ();
5287 if (r == Gtk::RESPONSE_OK) {
5288 Quantize quant (quantize_dialog->snap_start(),
5289 quantize_dialog->snap_end(),
5290 quantize_dialog->start_grid_size(),
5291 quantize_dialog->end_grid_size(),
5292 quantize_dialog->strength(),
5293 quantize_dialog->swing(),
5294 quantize_dialog->threshold());
5296 apply_midi_note_edit_op (quant, rs);
5301 Editor::legatize_region (bool shrink_only)
5304 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5309 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5311 if (rs.n_midi_regions() == 0) {
5315 Legatize legatize(shrink_only);
5316 apply_midi_note_edit_op (legatize, rs);
5320 Editor::transform_region ()
5323 transform_regions(get_regions_from_selection_and_entered ());
5328 Editor::transform_regions (const RegionSelection& rs)
5330 if (rs.n_midi_regions() == 0) {
5337 const int r = td.run();
5340 if (r == Gtk::RESPONSE_OK) {
5341 Transform transform(td.get());
5342 apply_midi_note_edit_op(transform, rs);
5347 Editor::transpose_region ()
5350 transpose_regions(get_regions_from_selection_and_entered ());
5355 Editor::transpose_regions (const RegionSelection& rs)
5357 if (rs.n_midi_regions() == 0) {
5362 int const r = d.run ();
5364 if (r == RESPONSE_ACCEPT) {
5365 Transpose transpose(d.semitones ());
5366 apply_midi_note_edit_op (transpose, rs);
5371 Editor::insert_patch_change (bool from_context)
5373 RegionSelection rs = get_regions_from_selection_and_entered ();
5379 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5381 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5382 there may be more than one, but the PatchChangeDialog can only offer
5383 one set of patch menus.
5385 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5387 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5388 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5390 if (d.run() == RESPONSE_CANCEL) {
5394 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5395 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5397 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5398 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5405 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5407 RegionSelection rs = get_regions_from_selection_and_entered ();
5413 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5414 bool in_command = false;
5419 int const N = rs.size ();
5421 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5422 RegionSelection::iterator tmp = r;
5425 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5427 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5430 progress->descend (1.0 / N);
5433 if (arv->audio_region()->apply (filter, progress) == 0) {
5435 playlist->clear_changes ();
5436 playlist->clear_owned_changes ();
5439 begin_reversible_command (command);
5443 if (filter.results.empty ()) {
5445 /* no regions returned; remove the old one */
5446 playlist->remove_region (arv->region ());
5450 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5452 /* first region replaces the old one */
5453 playlist->replace_region (arv->region(), *res, (*res)->position());
5457 while (res != filter.results.end()) {
5458 playlist->add_region (*res, (*res)->position());
5464 /* We might have removed regions, which alters other regions' layering_index,
5465 so we need to do a recursive diff here.
5467 vector<Command*> cmds;
5468 playlist->rdiff (cmds);
5469 _session->add_commands (cmds);
5471 _session->add_command(new StatefulDiffCommand (playlist));
5475 progress->ascend ();
5484 commit_reversible_command ();
5489 Editor::external_edit_region ()
5495 Editor::reset_region_gain_envelopes ()
5497 RegionSelection rs = get_regions_from_selection_and_entered ();
5499 if (!_session || rs.empty()) {
5503 bool in_command = false;
5505 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5506 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5508 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5509 XMLNode& before (alist->get_state());
5511 arv->audio_region()->set_default_envelope ();
5514 begin_reversible_command (_("reset region gain"));
5517 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5522 commit_reversible_command ();
5527 Editor::set_region_gain_visibility (RegionView* rv)
5529 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5531 arv->update_envelope_visibility();
5536 Editor::set_gain_envelope_visibility ()
5542 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5543 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5545 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5551 Editor::toggle_gain_envelope_active ()
5553 if (_ignore_region_action) {
5557 RegionSelection rs = get_regions_from_selection_and_entered ();
5559 if (!_session || rs.empty()) {
5563 bool in_command = false;
5565 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5566 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5568 arv->region()->clear_changes ();
5569 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5572 begin_reversible_command (_("region gain envelope active"));
5575 _session->add_command (new StatefulDiffCommand (arv->region()));
5580 commit_reversible_command ();
5585 Editor::toggle_region_lock ()
5587 if (_ignore_region_action) {
5591 RegionSelection rs = get_regions_from_selection_and_entered ();
5593 if (!_session || rs.empty()) {
5597 begin_reversible_command (_("toggle region lock"));
5599 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5600 (*i)->region()->clear_changes ();
5601 (*i)->region()->set_locked (!(*i)->region()->locked());
5602 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5605 commit_reversible_command ();
5609 Editor::toggle_region_video_lock ()
5611 if (_ignore_region_action) {
5615 RegionSelection rs = get_regions_from_selection_and_entered ();
5617 if (!_session || rs.empty()) {
5621 begin_reversible_command (_("Toggle Video Lock"));
5623 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5624 (*i)->region()->clear_changes ();
5625 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5626 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5629 commit_reversible_command ();
5633 Editor::toggle_region_lock_style ()
5635 if (_ignore_region_action) {
5639 RegionSelection rs = get_regions_from_selection_and_entered ();
5641 if (!_session || rs.empty()) {
5645 begin_reversible_command (_("region lock style"));
5647 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5648 (*i)->region()->clear_changes ();
5649 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5650 (*i)->region()->set_position_lock_style (ns);
5651 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5654 commit_reversible_command ();
5658 Editor::toggle_opaque_region ()
5660 if (_ignore_region_action) {
5664 RegionSelection rs = get_regions_from_selection_and_entered ();
5666 if (!_session || rs.empty()) {
5670 begin_reversible_command (_("change region opacity"));
5672 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5673 (*i)->region()->clear_changes ();
5674 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5675 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5678 commit_reversible_command ();
5682 Editor::toggle_record_enable ()
5684 bool new_state = false;
5686 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5687 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5690 if (!rtav->is_track())
5694 new_state = !rtav->track()->record_enabled();
5698 rtav->track()->set_record_enabled (new_state, Controllable::UseGroup);
5703 Editor::toggle_solo ()
5705 bool new_state = false;
5707 boost::shared_ptr<RouteList> rl (new RouteList);
5709 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5710 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5717 new_state = !rtav->route()->soloed ();
5721 rl->push_back (rtav->route());
5724 _session->set_solo (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
5728 Editor::toggle_mute ()
5730 bool new_state = false;
5732 boost::shared_ptr<RouteList> rl (new RouteList);
5734 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5735 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5742 new_state = !rtav->route()->muted();
5746 rl->push_back (rtav->route());
5749 _session->set_mute (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
5753 Editor::toggle_solo_isolate ()
5759 Editor::fade_range ()
5761 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5763 begin_reversible_command (_("fade range"));
5765 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5766 (*i)->fade_range (selection->time);
5769 commit_reversible_command ();
5774 Editor::set_fade_length (bool in)
5776 RegionSelection rs = get_regions_from_selection_and_entered ();
5782 /* we need a region to measure the offset from the start */
5784 RegionView* rv = rs.front ();
5786 framepos_t pos = get_preferred_edit_position();
5790 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5791 /* edit point is outside the relevant region */
5796 if (pos <= rv->region()->position()) {
5800 len = pos - rv->region()->position();
5801 cmd = _("set fade in length");
5803 if (pos >= rv->region()->last_frame()) {
5807 len = rv->region()->last_frame() - pos;
5808 cmd = _("set fade out length");
5811 bool in_command = false;
5813 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5814 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5820 boost::shared_ptr<AutomationList> alist;
5822 alist = tmp->audio_region()->fade_in();
5824 alist = tmp->audio_region()->fade_out();
5827 XMLNode &before = alist->get_state();
5830 tmp->audio_region()->set_fade_in_length (len);
5831 tmp->audio_region()->set_fade_in_active (true);
5833 tmp->audio_region()->set_fade_out_length (len);
5834 tmp->audio_region()->set_fade_out_active (true);
5838 begin_reversible_command (cmd);
5841 XMLNode &after = alist->get_state();
5842 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5846 commit_reversible_command ();
5851 Editor::set_fade_in_shape (FadeShape shape)
5853 RegionSelection rs = get_regions_from_selection_and_entered ();
5858 bool in_command = false;
5860 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5861 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5867 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5868 XMLNode &before = alist->get_state();
5870 tmp->audio_region()->set_fade_in_shape (shape);
5873 begin_reversible_command (_("set fade in shape"));
5876 XMLNode &after = alist->get_state();
5877 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5881 commit_reversible_command ();
5886 Editor::set_fade_out_shape (FadeShape shape)
5888 RegionSelection rs = get_regions_from_selection_and_entered ();
5893 bool in_command = false;
5895 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5896 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5902 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5903 XMLNode &before = alist->get_state();
5905 tmp->audio_region()->set_fade_out_shape (shape);
5908 begin_reversible_command (_("set fade out shape"));
5911 XMLNode &after = alist->get_state();
5912 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5916 commit_reversible_command ();
5921 Editor::set_fade_in_active (bool yn)
5923 RegionSelection rs = get_regions_from_selection_and_entered ();
5928 bool in_command = false;
5930 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5931 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5938 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5940 ar->clear_changes ();
5941 ar->set_fade_in_active (yn);
5944 begin_reversible_command (_("set fade in active"));
5947 _session->add_command (new StatefulDiffCommand (ar));
5951 commit_reversible_command ();
5956 Editor::set_fade_out_active (bool yn)
5958 RegionSelection rs = get_regions_from_selection_and_entered ();
5963 bool in_command = false;
5965 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5966 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5972 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5974 ar->clear_changes ();
5975 ar->set_fade_out_active (yn);
5978 begin_reversible_command (_("set fade out active"));
5981 _session->add_command(new StatefulDiffCommand (ar));
5985 commit_reversible_command ();
5990 Editor::toggle_region_fades (int dir)
5992 if (_ignore_region_action) {
5996 boost::shared_ptr<AudioRegion> ar;
5999 RegionSelection rs = get_regions_from_selection_and_entered ();
6005 RegionSelection::iterator i;
6006 for (i = rs.begin(); i != rs.end(); ++i) {
6007 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6009 yn = ar->fade_out_active ();
6011 yn = ar->fade_in_active ();
6017 if (i == rs.end()) {
6021 /* XXX should this undo-able? */
6022 bool in_command = false;
6024 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6025 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6028 ar->clear_changes ();
6030 if (dir == 1 || dir == 0) {
6031 ar->set_fade_in_active (!yn);
6034 if (dir == -1 || dir == 0) {
6035 ar->set_fade_out_active (!yn);
6038 begin_reversible_command (_("toggle fade active"));
6041 _session->add_command(new StatefulDiffCommand (ar));
6045 commit_reversible_command ();
6050 /** Update region fade visibility after its configuration has been changed */
6052 Editor::update_region_fade_visibility ()
6054 bool _fade_visibility = _session->config.get_show_region_fades ();
6056 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6057 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6059 if (_fade_visibility) {
6060 v->audio_view()->show_all_fades ();
6062 v->audio_view()->hide_all_fades ();
6069 Editor::set_edit_point ()
6074 if (!mouse_frame (where, ignored)) {
6080 if (selection->markers.empty()) {
6082 mouse_add_new_marker (where);
6087 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6090 loc->move_to (where);
6096 Editor::set_playhead_cursor ()
6098 if (entered_marker) {
6099 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6104 if (!mouse_frame (where, ignored)) {
6111 _session->request_locate (where, _session->transport_rolling());
6115 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6116 cancel_time_selection();
6121 Editor::split_region ()
6123 if (_drags->active ()) {
6127 //if a range is selected, separate it
6128 if ( !selection->time.empty()) {
6129 separate_regions_between (selection->time);
6133 //if no range was selected, try to find some regions to split
6134 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6136 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6138 framepos_t where = get_preferred_edit_position ();
6144 split_regions_at (where, rs);
6148 struct EditorOrderRouteSorter {
6149 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6150 return a->order_key () < b->order_key ();
6155 Editor::select_next_route()
6157 if (selection->tracks.empty()) {
6158 selection->set (track_views.front());
6162 TimeAxisView* current = selection->tracks.front();
6166 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6167 if (*i == current) {
6169 if (i != track_views.end()) {
6172 current = (*(track_views.begin()));
6173 //selection->set (*(track_views.begin()));
6178 rui = dynamic_cast<RouteUI *>(current);
6179 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6181 selection->set(current);
6183 ensure_time_axis_view_is_visible (*current, false);
6187 Editor::select_prev_route()
6189 if (selection->tracks.empty()) {
6190 selection->set (track_views.front());
6194 TimeAxisView* current = selection->tracks.front();
6198 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6199 if (*i == current) {
6201 if (i != track_views.rend()) {
6204 current = *(track_views.rbegin());
6209 rui = dynamic_cast<RouteUI *>(current);
6210 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6212 selection->set (current);
6214 ensure_time_axis_view_is_visible (*current, false);
6218 Editor::set_loop_from_selection (bool play)
6220 if (_session == 0) {
6224 framepos_t start, end;
6225 if (!get_selection_extents ( start, end))
6228 set_loop_range (start, end, _("set loop range from selection"));
6231 _session->request_play_loop (true, true);
6236 Editor::set_loop_from_region (bool play)
6238 framepos_t start, end;
6239 if (!get_selection_extents ( start, end))
6242 set_loop_range (start, end, _("set loop range from region"));
6245 _session->request_locate (start, true);
6246 _session->request_play_loop (true);
6251 Editor::set_punch_from_selection ()
6253 if (_session == 0) {
6257 framepos_t start, end;
6258 if (!get_selection_extents ( start, end))
6261 set_punch_range (start, end, _("set punch range from selection"));
6265 Editor::set_session_extents_from_selection ()
6267 if (_session == 0) {
6271 framepos_t start, end;
6272 if (!get_selection_extents ( start, end))
6276 if ((loc = _session->locations()->session_range_location()) == 0) {
6277 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6279 XMLNode &before = loc->get_state();
6281 _session->set_session_extents ( start, end );
6283 XMLNode &after = loc->get_state();
6285 begin_reversible_command (_("set session start/end from selection"));
6287 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6289 commit_reversible_command ();
6294 Editor::set_punch_start_from_edit_point ()
6298 framepos_t start = 0;
6299 framepos_t end = max_framepos;
6301 //use the existing punch end, if any
6302 Location* tpl = transport_punch_location();
6307 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6308 start = _session->audible_frame();
6310 start = get_preferred_edit_position();
6313 //snap the selection start/end
6316 //if there's not already a sensible selection endpoint, go "forever"
6317 if ( start > end ) {
6321 set_punch_range (start, end, _("set punch start from EP"));
6327 Editor::set_punch_end_from_edit_point ()
6331 framepos_t start = 0;
6332 framepos_t end = max_framepos;
6334 //use the existing punch start, if any
6335 Location* tpl = transport_punch_location();
6337 start = tpl->start();
6340 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6341 end = _session->audible_frame();
6343 end = get_preferred_edit_position();
6346 //snap the selection start/end
6349 set_punch_range (start, end, _("set punch end from EP"));
6355 Editor::set_loop_start_from_edit_point ()
6359 framepos_t start = 0;
6360 framepos_t end = max_framepos;
6362 //use the existing loop end, if any
6363 Location* tpl = transport_loop_location();
6368 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6369 start = _session->audible_frame();
6371 start = get_preferred_edit_position();
6374 //snap the selection start/end
6377 //if there's not already a sensible selection endpoint, go "forever"
6378 if ( start > end ) {
6382 set_loop_range (start, end, _("set loop start from EP"));
6388 Editor::set_loop_end_from_edit_point ()
6392 framepos_t start = 0;
6393 framepos_t end = max_framepos;
6395 //use the existing loop start, if any
6396 Location* tpl = transport_loop_location();
6398 start = tpl->start();
6401 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6402 end = _session->audible_frame();
6404 end = get_preferred_edit_position();
6407 //snap the selection start/end
6410 set_loop_range (start, end, _("set loop end from EP"));
6415 Editor::set_punch_from_region ()
6417 framepos_t start, end;
6418 if (!get_selection_extents ( start, end))
6421 set_punch_range (start, end, _("set punch range from region"));
6425 Editor::pitch_shift_region ()
6427 RegionSelection rs = get_regions_from_selection_and_entered ();
6429 RegionSelection audio_rs;
6430 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6431 if (dynamic_cast<AudioRegionView*> (*i)) {
6432 audio_rs.push_back (*i);
6436 if (audio_rs.empty()) {
6440 pitch_shift (audio_rs, 1.2);
6444 Editor::set_tempo_from_region ()
6446 RegionSelection rs = get_regions_from_selection_and_entered ();
6448 if (!_session || rs.empty()) {
6452 RegionView* rv = rs.front();
6454 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6458 Editor::use_range_as_bar ()
6460 framepos_t start, end;
6461 if (get_edit_op_range (start, end)) {
6462 define_one_bar (start, end);
6467 Editor::define_one_bar (framepos_t start, framepos_t end)
6469 framepos_t length = end - start;
6471 const Meter& m (_session->tempo_map().meter_at (start));
6473 /* length = 1 bar */
6475 /* We're going to deliver a constant tempo here,
6476 so we can use frames per beat to determine length.
6477 now we want frames per beat.
6478 we have frames per bar, and beats per bar, so ...
6481 /* XXXX METER MATH */
6483 double frames_per_beat = length / m.divisions_per_bar();
6485 /* beats per minute = */
6487 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6489 /* now decide whether to:
6491 (a) set global tempo
6492 (b) add a new tempo marker
6496 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6498 bool do_global = false;
6500 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6502 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6503 at the start, or create a new marker
6506 vector<string> options;
6507 options.push_back (_("Cancel"));
6508 options.push_back (_("Add new marker"));
6509 options.push_back (_("Set global tempo"));
6512 _("Define one bar"),
6513 _("Do you want to set the global tempo or add a new tempo marker?"),
6517 c.set_default_response (2);
6533 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6534 if the marker is at the region starter, change it, otherwise add
6539 begin_reversible_command (_("set tempo from region"));
6540 XMLNode& before (_session->tempo_map().get_state());
6543 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6544 } else if (t.frame() == start) {
6545 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6547 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start, TempoSection::Constant);
6550 XMLNode& after (_session->tempo_map().get_state());
6552 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6553 commit_reversible_command ();
6557 Editor::split_region_at_transients ()
6559 AnalysisFeatureList positions;
6561 RegionSelection rs = get_regions_from_selection_and_entered ();
6563 if (!_session || rs.empty()) {
6567 begin_reversible_command (_("split regions"));
6569 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6571 RegionSelection::iterator tmp;
6576 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6579 ar->transients (positions);
6580 split_region_at_points ((*i)->region(), positions, true);
6587 commit_reversible_command ();
6592 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6594 bool use_rhythmic_rodent = false;
6596 boost::shared_ptr<Playlist> pl = r->playlist();
6598 list<boost::shared_ptr<Region> > new_regions;
6604 if (positions.empty()) {
6608 if (positions.size() > 20 && can_ferret) {
6609 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);
6610 MessageDialog msg (msgstr,
6613 Gtk::BUTTONS_OK_CANCEL);
6616 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6617 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6619 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6622 msg.set_title (_("Excessive split?"));
6625 int response = msg.run();
6631 case RESPONSE_APPLY:
6632 use_rhythmic_rodent = true;
6639 if (use_rhythmic_rodent) {
6640 show_rhythm_ferret ();
6644 AnalysisFeatureList::const_iterator x;
6646 pl->clear_changes ();
6647 pl->clear_owned_changes ();
6649 x = positions.begin();
6651 if (x == positions.end()) {
6656 pl->remove_region (r);
6660 framepos_t rstart = r->first_frame ();
6661 framepos_t rend = r->last_frame ();
6663 while (x != positions.end()) {
6665 /* deal with positons that are out of scope of present region bounds */
6666 if (*x <= rstart || *x > rend) {
6671 /* file start = original start + how far we from the initial position ? */
6673 framepos_t file_start = r->start() + pos;
6675 /* length = next position - current position */
6677 framepos_t len = (*x) - pos - rstart;
6679 /* XXX we do we really want to allow even single-sample regions?
6680 * shouldn't we have some kind of lower limit on region size?
6689 if (RegionFactory::region_name (new_name, r->name())) {
6693 /* do NOT announce new regions 1 by one, just wait till they are all done */
6697 plist.add (ARDOUR::Properties::start, file_start);
6698 plist.add (ARDOUR::Properties::length, len);
6699 plist.add (ARDOUR::Properties::name, new_name);
6700 plist.add (ARDOUR::Properties::layer, 0);
6701 // TODO set transients_offset
6703 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6704 /* because we set annouce to false, manually add the new region to the
6707 RegionFactory::map_add (nr);
6709 pl->add_region (nr, rstart + pos);
6712 new_regions.push_front(nr);
6721 RegionFactory::region_name (new_name, r->name());
6723 /* Add the final region */
6726 plist.add (ARDOUR::Properties::start, r->start() + pos);
6727 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6728 plist.add (ARDOUR::Properties::name, new_name);
6729 plist.add (ARDOUR::Properties::layer, 0);
6731 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6732 /* because we set annouce to false, manually add the new region to the
6735 RegionFactory::map_add (nr);
6736 pl->add_region (nr, r->position() + pos);
6739 new_regions.push_front(nr);
6744 /* We might have removed regions, which alters other regions' layering_index,
6745 so we need to do a recursive diff here.
6747 vector<Command*> cmds;
6749 _session->add_commands (cmds);
6751 _session->add_command (new StatefulDiffCommand (pl));
6755 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6756 set_selected_regionview_from_region_list ((*i), Selection::Add);
6762 Editor::place_transient()
6768 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6774 framepos_t where = get_preferred_edit_position();
6776 begin_reversible_command (_("place transient"));
6778 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6779 (*r)->region()->add_transient(where);
6782 commit_reversible_command ();
6786 Editor::remove_transient(ArdourCanvas::Item* item)
6792 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6795 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6796 _arv->remove_transient (*(float*) _line->get_data ("position"));
6800 Editor::snap_regions_to_grid ()
6802 list <boost::shared_ptr<Playlist > > used_playlists;
6804 RegionSelection rs = get_regions_from_selection_and_entered ();
6806 if (!_session || rs.empty()) {
6810 begin_reversible_command (_("snap regions to grid"));
6812 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6814 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6816 if (!pl->frozen()) {
6817 /* we haven't seen this playlist before */
6819 /* remember used playlists so we can thaw them later */
6820 used_playlists.push_back(pl);
6824 framepos_t start_frame = (*r)->region()->first_frame ();
6825 snap_to (start_frame);
6826 (*r)->region()->set_position (start_frame);
6829 while (used_playlists.size() > 0) {
6830 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6832 used_playlists.pop_front();
6835 commit_reversible_command ();
6839 Editor::close_region_gaps ()
6841 list <boost::shared_ptr<Playlist > > used_playlists;
6843 RegionSelection rs = get_regions_from_selection_and_entered ();
6845 if (!_session || rs.empty()) {
6849 Dialog dialog (_("Close Region Gaps"));
6852 table.set_spacings (12);
6853 table.set_border_width (12);
6854 Label* l = manage (left_aligned_label (_("Crossfade length")));
6855 table.attach (*l, 0, 1, 0, 1);
6857 SpinButton spin_crossfade (1, 0);
6858 spin_crossfade.set_range (0, 15);
6859 spin_crossfade.set_increments (1, 1);
6860 spin_crossfade.set_value (5);
6861 table.attach (spin_crossfade, 1, 2, 0, 1);
6863 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6865 l = manage (left_aligned_label (_("Pull-back length")));
6866 table.attach (*l, 0, 1, 1, 2);
6868 SpinButton spin_pullback (1, 0);
6869 spin_pullback.set_range (0, 100);
6870 spin_pullback.set_increments (1, 1);
6871 spin_pullback.set_value(30);
6872 table.attach (spin_pullback, 1, 2, 1, 2);
6874 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6876 dialog.get_vbox()->pack_start (table);
6877 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6878 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6881 if (dialog.run () == RESPONSE_CANCEL) {
6885 framepos_t crossfade_len = spin_crossfade.get_value();
6886 framepos_t pull_back_frames = spin_pullback.get_value();
6888 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6889 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6891 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6893 begin_reversible_command (_("close region gaps"));
6896 boost::shared_ptr<Region> last_region;
6898 rs.sort_by_position_and_track();
6900 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6902 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6904 if (!pl->frozen()) {
6905 /* we haven't seen this playlist before */
6907 /* remember used playlists so we can thaw them later */
6908 used_playlists.push_back(pl);
6912 framepos_t position = (*r)->region()->position();
6914 if (idx == 0 || position < last_region->position()){
6915 last_region = (*r)->region();
6920 (*r)->region()->trim_front( (position - pull_back_frames));
6921 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6923 last_region = (*r)->region();
6928 while (used_playlists.size() > 0) {
6929 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6931 used_playlists.pop_front();
6934 commit_reversible_command ();
6938 Editor::tab_to_transient (bool forward)
6940 AnalysisFeatureList positions;
6942 RegionSelection rs = get_regions_from_selection_and_entered ();
6948 framepos_t pos = _session->audible_frame ();
6950 if (!selection->tracks.empty()) {
6952 /* don't waste time searching for transients in duplicate playlists.
6955 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6957 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6959 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6962 boost::shared_ptr<Track> tr = rtv->track();
6964 boost::shared_ptr<Playlist> pl = tr->playlist ();
6966 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6969 positions.push_back (result);
6982 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6983 (*r)->region()->get_transients (positions);
6987 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6990 AnalysisFeatureList::iterator x;
6992 for (x = positions.begin(); x != positions.end(); ++x) {
6998 if (x != positions.end ()) {
6999 _session->request_locate (*x);
7003 AnalysisFeatureList::reverse_iterator x;
7005 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7011 if (x != positions.rend ()) {
7012 _session->request_locate (*x);
7018 Editor::playhead_forward_to_grid ()
7024 framepos_t pos = playhead_cursor->current_frame ();
7025 if (pos < max_framepos - 1) {
7027 snap_to_internal (pos, RoundUpAlways, false);
7028 _session->request_locate (pos);
7034 Editor::playhead_backward_to_grid ()
7040 framepos_t pos = playhead_cursor->current_frame ();
7043 snap_to_internal (pos, RoundDownAlways, false);
7044 _session->request_locate (pos);
7049 Editor::set_track_height (Height h)
7051 TrackSelection& ts (selection->tracks);
7053 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7054 (*x)->set_height_enum (h);
7059 Editor::toggle_tracks_active ()
7061 TrackSelection& ts (selection->tracks);
7063 bool target = false;
7069 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7070 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7074 target = !rtv->_route->active();
7077 rtv->_route->set_active (target, this);
7083 Editor::remove_tracks ()
7085 /* this will delete GUI objects that may be the subject of an event
7086 handler in which this method is called. Defer actual deletion to the
7087 next idle callback, when all event handling is finished.
7089 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7093 Editor::idle_remove_tracks ()
7095 Session::StateProtector sp (_session);
7097 return false; /* do not call again */
7101 Editor::_remove_tracks ()
7103 TrackSelection& ts (selection->tracks);
7109 vector<string> choices;
7113 const char* trackstr;
7115 vector<boost::shared_ptr<Route> > routes;
7116 bool special_bus = false;
7118 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7119 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7123 if (rtv->is_track()) {
7128 routes.push_back (rtv->_route);
7130 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7135 if (special_bus && !Config->get_allow_special_bus_removal()) {
7136 MessageDialog msg (_("That would be bad news ...."),
7140 msg.set_secondary_text (string_compose (_(
7141 "Removing the master or monitor bus is such a bad idea\n\
7142 that %1 is not going to allow it.\n\
7144 If you really want to do this sort of thing\n\
7145 edit your ardour.rc file to set the\n\
7146 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7153 if (ntracks + nbusses == 0) {
7157 trackstr = P_("track", "tracks", ntracks);
7158 busstr = P_("bus", "busses", nbusses);
7162 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7163 "(You may also lose the playlists associated with the %2)\n\n"
7164 "This action cannot be undone, and the session file will be overwritten!"),
7165 ntracks, trackstr, nbusses, busstr);
7167 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7168 "(You may also lose the playlists associated with the %2)\n\n"
7169 "This action cannot be undone, and the session file will be overwritten!"),
7172 } else if (nbusses) {
7173 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7174 "This action cannot be undone, and the session file will be overwritten"),
7178 choices.push_back (_("No, do nothing."));
7179 if (ntracks + nbusses > 1) {
7180 choices.push_back (_("Yes, remove them."));
7182 choices.push_back (_("Yes, remove it."));
7187 title = string_compose (_("Remove %1"), trackstr);
7189 title = string_compose (_("Remove %1"), busstr);
7192 Choice prompter (title, prompt, choices);
7194 if (prompter.run () != 1) {
7199 DisplaySuspender ds;
7200 boost::shared_ptr<RouteList> rl (new RouteList);
7201 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7204 _session->remove_routes (rl);
7206 /* TrackSelection and RouteList leave scope,
7207 * destructors are called,
7208 * diskstream drops references, save_state is called (again for every track)
7213 Editor::do_insert_time ()
7215 if (selection->tracks.empty()) {
7219 InsertRemoveTimeDialog d (*this);
7220 int response = d.run ();
7222 if (response != RESPONSE_OK) {
7226 if (d.distance() == 0) {
7231 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7233 d.intersected_region_action (),
7237 d.move_glued_markers(),
7238 d.move_locked_markers(),
7244 Editor::insert_time (
7245 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7246 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7250 if (Config->get_edit_mode() == Lock) {
7253 bool in_command = false;
7255 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7257 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7261 /* don't operate on any playlist more than once, which could
7262 * happen if "all playlists" is enabled, but there is more
7263 * than 1 track using playlists "from" a given track.
7266 set<boost::shared_ptr<Playlist> > pl;
7268 if (all_playlists) {
7269 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7270 if (rtav && rtav->track ()) {
7271 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7272 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7277 if ((*x)->playlist ()) {
7278 pl.insert ((*x)->playlist ());
7282 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7284 (*i)->clear_changes ();
7285 (*i)->clear_owned_changes ();
7287 if (opt == SplitIntersected) {
7291 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7294 begin_reversible_command (_("insert time"));
7297 vector<Command*> cmds;
7299 _session->add_commands (cmds);
7301 _session->add_command (new StatefulDiffCommand (*i));
7305 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7308 begin_reversible_command (_("insert time"));
7311 rtav->route ()->shift (pos, frames);
7318 XMLNode& before (_session->locations()->get_state());
7319 Locations::LocationList copy (_session->locations()->list());
7321 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7323 Locations::LocationList::const_iterator tmp;
7325 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7326 bool const was_locked = (*i)->locked ();
7327 if (locked_markers_too) {
7331 if ((*i)->start() >= pos) {
7332 // move end first, in case we're moving by more than the length of the range
7333 if (!(*i)->is_mark()) {
7334 (*i)->set_end ((*i)->end() + frames);
7336 (*i)->set_start ((*i)->start() + frames);
7348 begin_reversible_command (_("insert time"));
7351 XMLNode& after (_session->locations()->get_state());
7352 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7358 begin_reversible_command (_("insert time"));
7361 XMLNode& before (_session->tempo_map().get_state());
7362 _session->tempo_map().insert_time (pos, frames);
7363 XMLNode& after (_session->tempo_map().get_state());
7364 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7368 commit_reversible_command ();
7373 Editor::do_remove_time ()
7375 if (selection->tracks.empty()) {
7379 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7380 InsertRemoveTimeDialog d (*this, true);
7382 int response = d.run ();
7384 if (response != RESPONSE_OK) {
7388 framecnt_t distance = d.distance();
7390 if (distance == 0) {
7400 d.move_glued_markers(),
7401 d.move_locked_markers(),
7407 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7408 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7410 if (Config->get_edit_mode() == Lock) {
7411 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7414 bool in_command = false;
7416 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7418 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7422 XMLNode &before = pl->get_state();
7424 std::list<AudioRange> rl;
7425 AudioRange ar(pos, pos+frames, 0);
7428 pl->shift (pos, -frames, true, ignore_music_glue);
7431 begin_reversible_command (_("remove time"));
7434 XMLNode &after = pl->get_state();
7436 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7440 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7443 begin_reversible_command (_("remove time"));
7446 rtav->route ()->shift (pos, -frames);
7450 std::list<Location*> loc_kill_list;
7455 XMLNode& before (_session->locations()->get_state());
7456 Locations::LocationList copy (_session->locations()->list());
7458 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7459 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7461 bool const was_locked = (*i)->locked ();
7462 if (locked_markers_too) {
7466 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7467 if ((*i)->end() >= pos
7468 && (*i)->end() < pos+frames
7469 && (*i)->start() >= pos
7470 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7472 loc_kill_list.push_back(*i);
7473 } else { // only start or end is included, try to do the right thing
7474 // move start before moving end, to avoid trying to move the end to before the start
7475 // if we're removing more time than the length of the range
7476 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7477 // start is within cut
7478 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7480 } else if ((*i)->start() >= pos+frames) {
7481 // start (and thus entire range) lies beyond end of cut
7482 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7485 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7486 // end is inside cut
7487 (*i)->set_end (pos); // bring the end to the cut
7489 } else if ((*i)->end() >= pos+frames) {
7490 // end is beyond end of cut
7491 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7496 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7497 loc_kill_list.push_back(*i);
7499 } else if ((*i)->start() >= pos) {
7500 (*i)->set_start ((*i)->start() -frames);
7510 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7511 _session->locations()->remove( *i );
7516 begin_reversible_command (_("remove time"));
7519 XMLNode& after (_session->locations()->get_state());
7520 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7525 XMLNode& before (_session->tempo_map().get_state());
7527 if (_session->tempo_map().remove_time (pos, frames) ) {
7529 begin_reversible_command (_("remove time"));
7532 XMLNode& after (_session->tempo_map().get_state());
7533 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7538 commit_reversible_command ();
7543 Editor::fit_selection ()
7545 if (!selection->tracks.empty()) {
7546 fit_tracks (selection->tracks);
7550 /* no selected tracks - use tracks with selected regions */
7552 if (!selection->regions.empty()) {
7553 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7554 tvl.push_back (&(*r)->get_time_axis_view ());
7560 } else if (internal_editing()) {
7561 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7564 if (entered_track) {
7565 tvl.push_back (entered_track);
7574 Editor::fit_tracks (TrackViewList & tracks)
7576 if (tracks.empty()) {
7580 uint32_t child_heights = 0;
7581 int visible_tracks = 0;
7583 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7585 if (!(*t)->marked_for_display()) {
7589 child_heights += (*t)->effective_height() - (*t)->current_height();
7593 /* compute the per-track height from:
7595 total canvas visible height -
7596 height that will be taken by visible children of selected
7597 tracks - height of the ruler/hscroll area
7599 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7600 double first_y_pos = DBL_MAX;
7602 if (h < TimeAxisView::preset_height (HeightSmall)) {
7603 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7604 /* too small to be displayed */
7608 undo_visual_stack.push_back (current_visual_state (true));
7609 PBD::Unwinder<bool> nsv (no_save_visual, true);
7611 /* build a list of all tracks, including children */
7614 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7616 TimeAxisView::Children c = (*i)->get_child_list ();
7617 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7618 all.push_back (j->get());
7623 // find selection range.
7624 // if someone knows how to user TrackViewList::iterator for this
7626 int selected_top = -1;
7627 int selected_bottom = -1;
7629 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7630 if ((*t)->marked_for_display ()) {
7631 if (tracks.contains(*t)) {
7632 if (selected_top == -1) {
7635 selected_bottom = i;
7641 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7642 if ((*t)->marked_for_display ()) {
7643 if (tracks.contains(*t)) {
7644 (*t)->set_height (h);
7645 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7647 if (i > selected_top && i < selected_bottom) {
7648 hide_track_in_display (*t);
7655 set the controls_layout height now, because waiting for its size
7656 request signal handler will cause the vertical adjustment setting to fail
7659 controls_layout.property_height () = _full_canvas_height;
7660 vertical_adjustment.set_value (first_y_pos);
7662 redo_visual_stack.push_back (current_visual_state (true));
7664 visible_tracks_selector.set_text (_("Sel"));
7668 Editor::save_visual_state (uint32_t n)
7670 while (visual_states.size() <= n) {
7671 visual_states.push_back (0);
7674 if (visual_states[n] != 0) {
7675 delete visual_states[n];
7678 visual_states[n] = current_visual_state (true);
7683 Editor::goto_visual_state (uint32_t n)
7685 if (visual_states.size() <= n) {
7689 if (visual_states[n] == 0) {
7693 use_visual_state (*visual_states[n]);
7697 Editor::start_visual_state_op (uint32_t n)
7699 save_visual_state (n);
7701 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7703 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7704 pup->set_text (buf);
7709 Editor::cancel_visual_state_op (uint32_t n)
7711 goto_visual_state (n);
7715 Editor::toggle_region_mute ()
7717 if (_ignore_region_action) {
7721 RegionSelection rs = get_regions_from_selection_and_entered ();
7727 if (rs.size() > 1) {
7728 begin_reversible_command (_("mute regions"));
7730 begin_reversible_command (_("mute region"));
7733 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7735 (*i)->region()->playlist()->clear_changes ();
7736 (*i)->region()->set_muted (!(*i)->region()->muted ());
7737 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7741 commit_reversible_command ();
7745 Editor::combine_regions ()
7747 /* foreach track with selected regions, take all selected regions
7748 and join them into a new region containing the subregions (as a
7752 typedef set<RouteTimeAxisView*> RTVS;
7755 if (selection->regions.empty()) {
7759 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7760 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7763 tracks.insert (rtv);
7767 begin_reversible_command (_("combine regions"));
7769 vector<RegionView*> new_selection;
7771 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7774 if ((rv = (*i)->combine_regions ()) != 0) {
7775 new_selection.push_back (rv);
7779 selection->clear_regions ();
7780 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7781 selection->add (*i);
7784 commit_reversible_command ();
7788 Editor::uncombine_regions ()
7790 typedef set<RouteTimeAxisView*> RTVS;
7793 if (selection->regions.empty()) {
7797 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7798 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7801 tracks.insert (rtv);
7805 begin_reversible_command (_("uncombine regions"));
7807 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7808 (*i)->uncombine_regions ();
7811 commit_reversible_command ();
7815 Editor::toggle_midi_input_active (bool flip_others)
7818 boost::shared_ptr<RouteList> rl (new RouteList);
7820 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7821 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7827 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7830 rl->push_back (rtav->route());
7831 onoff = !mt->input_active();
7835 _session->set_exclusive_input_active (rl, onoff, flip_others);
7842 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7844 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7845 lock_dialog->get_vbox()->pack_start (*padlock);
7847 ArdourButton* b = manage (new ArdourButton);
7848 b->set_name ("lock button");
7849 b->set_text (_("Click to unlock"));
7850 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7851 lock_dialog->get_vbox()->pack_start (*b);
7853 lock_dialog->get_vbox()->show_all ();
7854 lock_dialog->set_size_request (200, 200);
7857 delete _main_menu_disabler;
7858 _main_menu_disabler = new MainMenuDisabler;
7860 lock_dialog->present ();
7866 lock_dialog->hide ();
7868 delete _main_menu_disabler;
7869 _main_menu_disabler = 0;
7871 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7872 start_lock_event_timing ();
7877 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7879 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7883 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7885 Timers::TimerSuspender t;
7886 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7887 Gtkmm2ext::UI::instance()->flush_pending ();
7891 Editor::bring_all_sources_into_session ()
7898 ArdourDialog w (_("Moving embedded files into session folder"));
7899 w.get_vbox()->pack_start (msg);
7902 /* flush all pending GUI events because we're about to start copying
7906 Timers::TimerSuspender t;
7907 Gtkmm2ext::UI::instance()->flush_pending ();
7911 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));