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)
158 RegionSelection pre_selected_regions = selection->regions;
159 bool working_on_selection = !pre_selected_regions.empty();
161 list<boost::shared_ptr<Playlist> > used_playlists;
162 list<RouteTimeAxisView*> used_trackviews;
164 if (regions.empty()) {
168 begin_reversible_command (_("split"));
170 // if splitting a single region, and snap-to is using
171 // region boundaries, don't pay attention to them
173 if (regions.size() == 1) {
174 switch (_snap_type) {
175 case SnapToRegionStart:
176 case SnapToRegionSync:
177 case SnapToRegionEnd:
186 EditorFreeze(); /* Emit Signal */
189 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
191 RegionSelection::iterator tmp;
193 /* XXX this test needs to be more complicated, to make sure we really
194 have something to split.
197 if (!(*a)->region()->covers (where)) {
205 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
213 /* we haven't seen this playlist before */
215 /* remember used playlists so we can thaw them later */
216 used_playlists.push_back(pl);
218 TimeAxisView& tv = (*a)->get_time_axis_view();
219 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
221 used_trackviews.push_back (rtv);
228 pl->clear_changes ();
229 pl->split_region ((*a)->region(), where);
230 _session->add_command (new StatefulDiffCommand (pl));
236 latest_regionviews.clear ();
238 vector<sigc::connection> region_added_connections;
240 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
241 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
244 while (used_playlists.size() > 0) {
245 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
247 used_playlists.pop_front();
250 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
255 EditorThaw(); /* Emit Signal */
258 if (working_on_selection) {
259 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
261 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
262 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
263 /* There are three classes of regions that we might want selected after
264 splitting selected regions:
265 - regions selected before the split operation, and unaffected by it
266 - newly-created regions before the split
267 - newly-created regions after the split
270 if (rsas & Existing) {
271 // region selections that existed before the split.
272 selection->add ( pre_selected_regions );
275 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
276 if ((*ri)->region()->position() < where) {
277 // new regions created before the split
278 if (rsas & NewlyCreatedLeft) {
279 selection->add (*ri);
282 // new regions created after the split
283 if (rsas & NewlyCreatedRight) {
284 selection->add (*ri);
288 _ignore_follow_edits = false;
290 _ignore_follow_edits = true;
291 if( working_on_selection ) {
292 selection->add (latest_regionviews); //these are the new regions created after the split
294 _ignore_follow_edits = false;
297 commit_reversible_command ();
300 /** Move one extreme of the current range selection. If more than one range is selected,
301 * the start of the earliest range or the end of the latest range is moved.
303 * @param move_end true to move the end of the current range selection, false to move
305 * @param next true to move the extreme to the next region boundary, false to move to
309 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
311 if (selection->time.start() == selection->time.end_frame()) {
315 framepos_t start = selection->time.start ();
316 framepos_t end = selection->time.end_frame ();
318 /* the position of the thing we may move */
319 framepos_t pos = move_end ? end : start;
320 int dir = next ? 1 : -1;
322 /* so we don't find the current region again */
323 if (dir > 0 || pos > 0) {
327 framepos_t const target = get_region_boundary (pos, dir, true, false);
342 begin_reversible_selection_op (_("alter selection"));
343 selection->set_preserving_all_ranges (start, end);
344 commit_reversible_selection_op ();
348 Editor::nudge_forward_release (GdkEventButton* ev)
350 if (ev->state & Keyboard::PrimaryModifier) {
351 nudge_forward (false, true);
353 nudge_forward (false, false);
359 Editor::nudge_backward_release (GdkEventButton* ev)
361 if (ev->state & Keyboard::PrimaryModifier) {
362 nudge_backward (false, true);
364 nudge_backward (false, false);
371 Editor::nudge_forward (bool next, bool force_playhead)
374 framepos_t next_distance;
380 RegionSelection rs = get_regions_from_selection_and_entered ();
382 if (!force_playhead && !rs.empty()) {
384 begin_reversible_command (_("nudge regions forward"));
386 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
387 boost::shared_ptr<Region> r ((*i)->region());
389 distance = get_nudge_distance (r->position(), next_distance);
392 distance = next_distance;
396 r->set_position (r->position() + distance);
397 _session->add_command (new StatefulDiffCommand (r));
400 commit_reversible_command ();
403 } else if (!force_playhead && !selection->markers.empty()) {
406 bool in_command = false;
408 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
410 Location* loc = find_location_from_marker ((*i), is_start);
414 XMLNode& before (loc->get_state());
417 distance = get_nudge_distance (loc->start(), next_distance);
419 distance = next_distance;
421 if (max_framepos - distance > loc->start() + loc->length()) {
422 loc->set_start (loc->start() + distance);
424 loc->set_start (max_framepos - loc->length());
427 distance = get_nudge_distance (loc->end(), next_distance);
429 distance = next_distance;
431 if (max_framepos - distance > loc->end()) {
432 loc->set_end (loc->end() + distance);
434 loc->set_end (max_framepos);
438 begin_reversible_command (_("nudge location forward"));
441 XMLNode& after (loc->get_state());
442 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
447 commit_reversible_command ();
450 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
451 _session->request_locate (playhead_cursor->current_frame () + distance);
456 Editor::nudge_backward (bool next, bool force_playhead)
459 framepos_t next_distance;
465 RegionSelection rs = get_regions_from_selection_and_entered ();
467 if (!force_playhead && !rs.empty()) {
469 begin_reversible_command (_("nudge regions backward"));
471 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
472 boost::shared_ptr<Region> r ((*i)->region());
474 distance = get_nudge_distance (r->position(), next_distance);
477 distance = next_distance;
482 if (r->position() > distance) {
483 r->set_position (r->position() - distance);
487 _session->add_command (new StatefulDiffCommand (r));
490 commit_reversible_command ();
492 } else if (!force_playhead && !selection->markers.empty()) {
495 bool in_command = false;
497 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
499 Location* loc = find_location_from_marker ((*i), is_start);
503 XMLNode& before (loc->get_state());
506 distance = get_nudge_distance (loc->start(), next_distance);
508 distance = next_distance;
510 if (distance < loc->start()) {
511 loc->set_start (loc->start() - distance);
516 distance = get_nudge_distance (loc->end(), next_distance);
519 distance = next_distance;
522 if (distance < loc->end() - loc->length()) {
523 loc->set_end (loc->end() - distance);
525 loc->set_end (loc->length());
529 begin_reversible_command (_("nudge location forward"));
532 XMLNode& after (loc->get_state());
533 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
537 commit_reversible_command ();
542 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
544 if (playhead_cursor->current_frame () > distance) {
545 _session->request_locate (playhead_cursor->current_frame () - distance);
547 _session->goto_start();
553 Editor::nudge_forward_capture_offset ()
555 RegionSelection rs = get_regions_from_selection_and_entered ();
557 if (!_session || rs.empty()) {
561 begin_reversible_command (_("nudge forward"));
563 framepos_t const distance = _session->worst_output_latency();
565 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
566 boost::shared_ptr<Region> r ((*i)->region());
569 r->set_position (r->position() + distance);
570 _session->add_command(new StatefulDiffCommand (r));
573 commit_reversible_command ();
577 Editor::nudge_backward_capture_offset ()
579 RegionSelection rs = get_regions_from_selection_and_entered ();
581 if (!_session || rs.empty()) {
585 begin_reversible_command (_("nudge backward"));
587 framepos_t const distance = _session->worst_output_latency();
589 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
590 boost::shared_ptr<Region> r ((*i)->region());
594 if (r->position() > distance) {
595 r->set_position (r->position() - distance);
599 _session->add_command(new StatefulDiffCommand (r));
602 commit_reversible_command ();
605 struct RegionSelectionPositionSorter {
606 bool operator() (RegionView* a, RegionView* b) {
607 return a->region()->position() < b->region()->position();
612 Editor::sequence_regions ()
615 framepos_t r_end_prev;
623 RegionSelection rs = get_regions_from_selection_and_entered ();
624 rs.sort(RegionSelectionPositionSorter());
628 bool in_command = false;
630 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
631 boost::shared_ptr<Region> r ((*i)->region());
639 if(r->position_locked())
646 r->set_position(r_end_prev);
650 begin_reversible_command (_("sequence regions"));
653 _session->add_command (new StatefulDiffCommand (r));
655 r_end=r->position() + r->length();
661 commit_reversible_command ();
670 Editor::move_to_start ()
672 _session->goto_start ();
676 Editor::move_to_end ()
679 _session->request_locate (_session->current_end_frame());
683 Editor::build_region_boundary_cache ()
686 vector<RegionPoint> interesting_points;
687 boost::shared_ptr<Region> r;
688 TrackViewList tracks;
691 region_boundary_cache.clear ();
697 switch (_snap_type) {
698 case SnapToRegionStart:
699 interesting_points.push_back (Start);
701 case SnapToRegionEnd:
702 interesting_points.push_back (End);
704 case SnapToRegionSync:
705 interesting_points.push_back (SyncPoint);
707 case SnapToRegionBoundary:
708 interesting_points.push_back (Start);
709 interesting_points.push_back (End);
712 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
713 abort(); /*NOTREACHED*/
717 TimeAxisView *ontrack = 0;
720 if (!selection->tracks.empty()) {
721 tlist = selection->tracks.filter_to_unique_playlists ();
723 tlist = track_views.filter_to_unique_playlists ();
726 while (pos < _session->current_end_frame() && !at_end) {
729 framepos_t lpos = max_framepos;
731 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
733 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
734 if (*p == interesting_points.back()) {
737 /* move to next point type */
743 rpos = r->first_frame();
747 rpos = r->last_frame();
751 rpos = r->sync_position ();
759 RouteTimeAxisView *rtav;
761 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
762 if (rtav->track() != 0) {
763 speed = rtav->track()->speed();
767 rpos = track_frame_to_session_frame (rpos, speed);
773 /* prevent duplicates, but we don't use set<> because we want to be able
777 vector<framepos_t>::iterator ri;
779 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
785 if (ri == region_boundary_cache.end()) {
786 region_boundary_cache.push_back (rpos);
793 /* finally sort to be sure that the order is correct */
795 sort (region_boundary_cache.begin(), region_boundary_cache.end());
798 boost::shared_ptr<Region>
799 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
801 TrackViewList::iterator i;
802 framepos_t closest = max_framepos;
803 boost::shared_ptr<Region> ret;
807 framepos_t track_frame;
808 RouteTimeAxisView *rtav;
810 for (i = tracks.begin(); i != tracks.end(); ++i) {
813 boost::shared_ptr<Region> r;
816 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
817 if (rtav->track()!=0)
818 track_speed = rtav->track()->speed();
821 track_frame = session_frame_to_track_frame(frame, track_speed);
823 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
829 rpos = r->first_frame ();
833 rpos = r->last_frame ();
837 rpos = r->sync_position ();
841 // rpos is a "track frame", converting it to "_session frame"
842 rpos = track_frame_to_session_frame(rpos, track_speed);
845 distance = rpos - frame;
847 distance = frame - rpos;
850 if (distance < closest) {
862 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
864 framecnt_t distance = max_framepos;
865 framepos_t current_nearest = -1;
867 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
868 framepos_t contender;
871 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
877 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
881 d = ::llabs (pos - contender);
884 current_nearest = contender;
889 return current_nearest;
893 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
898 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
900 if (!selection->tracks.empty()) {
902 target = find_next_region_boundary (pos, dir, selection->tracks);
906 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
907 get_onscreen_tracks (tvl);
908 target = find_next_region_boundary (pos, dir, tvl);
910 target = find_next_region_boundary (pos, dir, track_views);
916 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
917 get_onscreen_tracks (tvl);
918 target = find_next_region_boundary (pos, dir, tvl);
920 target = find_next_region_boundary (pos, dir, track_views);
928 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
930 framepos_t pos = playhead_cursor->current_frame ();
937 // so we don't find the current region again..
938 if (dir > 0 || pos > 0) {
942 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
946 _session->request_locate (target);
950 Editor::cursor_to_next_region_boundary (bool with_selection)
952 cursor_to_region_boundary (with_selection, 1);
956 Editor::cursor_to_previous_region_boundary (bool with_selection)
958 cursor_to_region_boundary (with_selection, -1);
962 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
964 boost::shared_ptr<Region> r;
965 framepos_t pos = cursor->current_frame ();
971 TimeAxisView *ontrack = 0;
973 // so we don't find the current region again..
977 if (!selection->tracks.empty()) {
979 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
981 } else if (clicked_axisview) {
984 t.push_back (clicked_axisview);
986 r = find_next_region (pos, point, dir, t, &ontrack);
990 r = find_next_region (pos, point, dir, track_views, &ontrack);
999 pos = r->first_frame ();
1003 pos = r->last_frame ();
1007 pos = r->sync_position ();
1012 RouteTimeAxisView *rtav;
1014 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1015 if (rtav->track() != 0) {
1016 speed = rtav->track()->speed();
1020 pos = track_frame_to_session_frame(pos, speed);
1022 if (cursor == playhead_cursor) {
1023 _session->request_locate (pos);
1025 cursor->set_position (pos);
1030 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1032 cursor_to_region_point (cursor, point, 1);
1036 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1038 cursor_to_region_point (cursor, point, -1);
1042 Editor::cursor_to_selection_start (EditorCursor *cursor)
1046 switch (mouse_mode) {
1048 if (!selection->regions.empty()) {
1049 pos = selection->regions.start();
1054 if (!selection->time.empty()) {
1055 pos = selection->time.start ();
1063 if (cursor == playhead_cursor) {
1064 _session->request_locate (pos);
1066 cursor->set_position (pos);
1071 Editor::cursor_to_selection_end (EditorCursor *cursor)
1075 switch (mouse_mode) {
1077 if (!selection->regions.empty()) {
1078 pos = selection->regions.end_frame();
1083 if (!selection->time.empty()) {
1084 pos = selection->time.end_frame ();
1092 if (cursor == playhead_cursor) {
1093 _session->request_locate (pos);
1095 cursor->set_position (pos);
1100 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1110 if (selection->markers.empty()) {
1114 if (!mouse_frame (mouse, ignored)) {
1118 add_location_mark (mouse);
1121 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1125 framepos_t pos = loc->start();
1127 // so we don't find the current region again..
1128 if (dir > 0 || pos > 0) {
1132 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1136 loc->move_to (target);
1140 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1142 selected_marker_to_region_boundary (with_selection, 1);
1146 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1148 selected_marker_to_region_boundary (with_selection, -1);
1152 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1154 boost::shared_ptr<Region> r;
1159 if (!_session || selection->markers.empty()) {
1163 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1167 TimeAxisView *ontrack = 0;
1171 // so we don't find the current region again..
1175 if (!selection->tracks.empty()) {
1177 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1181 r = find_next_region (pos, point, dir, track_views, &ontrack);
1190 pos = r->first_frame ();
1194 pos = r->last_frame ();
1198 pos = r->adjust_to_sync (r->first_frame());
1203 RouteTimeAxisView *rtav;
1205 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1206 if (rtav->track() != 0) {
1207 speed = rtav->track()->speed();
1211 pos = track_frame_to_session_frame(pos, speed);
1217 Editor::selected_marker_to_next_region_point (RegionPoint point)
1219 selected_marker_to_region_point (point, 1);
1223 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1225 selected_marker_to_region_point (point, -1);
1229 Editor::selected_marker_to_selection_start ()
1235 if (!_session || selection->markers.empty()) {
1239 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1243 switch (mouse_mode) {
1245 if (!selection->regions.empty()) {
1246 pos = selection->regions.start();
1251 if (!selection->time.empty()) {
1252 pos = selection->time.start ();
1264 Editor::selected_marker_to_selection_end ()
1270 if (!_session || selection->markers.empty()) {
1274 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1278 switch (mouse_mode) {
1280 if (!selection->regions.empty()) {
1281 pos = selection->regions.end_frame();
1286 if (!selection->time.empty()) {
1287 pos = selection->time.end_frame ();
1299 Editor::scroll_playhead (bool forward)
1301 framepos_t pos = playhead_cursor->current_frame ();
1302 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1305 if (pos == max_framepos) {
1309 if (pos < max_framepos - delta) {
1328 _session->request_locate (pos);
1332 Editor::cursor_align (bool playhead_to_edit)
1338 if (playhead_to_edit) {
1340 if (selection->markers.empty()) {
1344 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1347 /* move selected markers to playhead */
1349 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1352 Location* loc = find_location_from_marker (*i, ignored);
1354 if (loc->is_mark()) {
1355 loc->set_start (playhead_cursor->current_frame ());
1357 loc->set (playhead_cursor->current_frame (),
1358 playhead_cursor->current_frame () + loc->length());
1365 Editor::scroll_backward (float pages)
1367 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1368 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1371 if (leftmost_frame < cnt) {
1374 frame = leftmost_frame - cnt;
1377 reset_x_origin (frame);
1381 Editor::scroll_forward (float pages)
1383 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1384 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1387 if (max_framepos - cnt < leftmost_frame) {
1388 frame = max_framepos - cnt;
1390 frame = leftmost_frame + cnt;
1393 reset_x_origin (frame);
1397 Editor::scroll_tracks_down ()
1399 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1400 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1401 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1404 vertical_adjustment.set_value (vert_value);
1408 Editor::scroll_tracks_up ()
1410 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1414 Editor::scroll_tracks_down_line ()
1416 double vert_value = vertical_adjustment.get_value() + 60;
1418 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1419 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1422 vertical_adjustment.set_value (vert_value);
1426 Editor::scroll_tracks_up_line ()
1428 reset_y_origin (vertical_adjustment.get_value() - 60);
1432 Editor::scroll_down_one_track (bool skip_child_views)
1434 TrackViewList::reverse_iterator next = track_views.rend();
1435 const double top_of_trackviews = vertical_adjustment.get_value();
1437 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1438 if ((*t)->hidden()) {
1442 /* If this is the upper-most visible trackview, we want to display
1443 * the one above it (next)
1445 * Note that covers_y_position() is recursive and includes child views
1447 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1450 if (skip_child_views) {
1453 /* automation lane (one level, non-recursive)
1455 * - if no automation lane exists -> move to next tack
1456 * - if the first (here: bottom-most) matches -> move to next tack
1457 * - if no y-axis match is found -> the current track is at the top
1458 * -> move to last (here: top-most) automation lane
1460 TimeAxisView::Children kids = (*t)->get_child_list();
1461 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1463 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1464 if ((*ci)->hidden()) {
1468 std::pair<TimeAxisView*,double> dev;
1469 dev = (*ci)->covers_y_position (top_of_trackviews);
1471 /* some automation lane is currently at the top */
1472 if (ci == kids.rbegin()) {
1473 /* first (bottom-most) autmation lane is at the top.
1474 * -> move to next track
1483 if (nkid != kids.rend()) {
1484 ensure_time_axis_view_is_visible (**nkid, true);
1492 /* move to the track below the first one that covers the */
1494 if (next != track_views.rend()) {
1495 ensure_time_axis_view_is_visible (**next, true);
1503 Editor::scroll_up_one_track (bool skip_child_views)
1505 TrackViewList::iterator prev = track_views.end();
1506 double top_of_trackviews = vertical_adjustment.get_value ();
1508 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1510 if ((*t)->hidden()) {
1514 /* find the trackview at the top of the trackview group
1516 * Note that covers_y_position() is recursive and includes child views
1518 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1521 if (skip_child_views) {
1524 /* automation lane (one level, non-recursive)
1526 * - if no automation lane exists -> move to prev tack
1527 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1528 * (actually last automation lane of previous track, see below)
1529 * - if first (top-most) lane is at the top -> move to this track
1530 * - else move up one lane
1532 TimeAxisView::Children kids = (*t)->get_child_list();
1533 TimeAxisView::Children::iterator pkid = kids.end();
1535 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1536 if ((*ci)->hidden()) {
1540 std::pair<TimeAxisView*,double> dev;
1541 dev = (*ci)->covers_y_position (top_of_trackviews);
1543 /* some automation lane is currently at the top */
1544 if (ci == kids.begin()) {
1545 /* first (top-most) autmation lane is at the top.
1546 * jump directly to this track's top
1548 ensure_time_axis_view_is_visible (**t, true);
1551 else if (pkid != kids.end()) {
1552 /* some other automation lane is at the top.
1553 * move up to prev automation lane.
1555 ensure_time_axis_view_is_visible (**pkid, true);
1558 assert(0); // not reached
1569 if (prev != track_views.end()) {
1570 // move to bottom-most automation-lane of the previous track
1571 TimeAxisView::Children kids = (*prev)->get_child_list();
1572 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1573 if (!skip_child_views) {
1574 // find the last visible lane
1575 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1576 if (!(*ci)->hidden()) {
1582 if (pkid != kids.rend()) {
1583 ensure_time_axis_view_is_visible (**pkid, true);
1585 ensure_time_axis_view_is_visible (**prev, true);
1594 Editor::scroll_left_step ()
1596 framepos_t xdelta = (current_page_samples() / 8);
1598 if (leftmost_frame > xdelta) {
1599 reset_x_origin (leftmost_frame - xdelta);
1607 Editor::scroll_right_step ()
1609 framepos_t xdelta = (current_page_samples() / 8);
1611 if (max_framepos - xdelta > leftmost_frame) {
1612 reset_x_origin (leftmost_frame + xdelta);
1614 reset_x_origin (max_framepos - current_page_samples());
1619 Editor::scroll_left_half_page ()
1621 framepos_t xdelta = (current_page_samples() / 2);
1622 if (leftmost_frame > xdelta) {
1623 reset_x_origin (leftmost_frame - xdelta);
1630 Editor::scroll_right_half_page ()
1632 framepos_t xdelta = (current_page_samples() / 2);
1633 if (max_framepos - xdelta > leftmost_frame) {
1634 reset_x_origin (leftmost_frame + xdelta);
1636 reset_x_origin (max_framepos - current_page_samples());
1643 Editor::tav_zoom_step (bool coarser)
1645 DisplaySuspender ds;
1649 if (selection->tracks.empty()) {
1652 ts = &selection->tracks;
1655 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1656 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1657 tv->step_height (coarser);
1662 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1664 DisplaySuspender ds;
1668 if (selection->tracks.empty() || force_all) {
1671 ts = &selection->tracks;
1674 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1675 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1676 uint32_t h = tv->current_height ();
1681 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1686 tv->set_height (h + 5);
1692 Editor::temporal_zoom_step_mouse_focus (bool coarser)
1694 Editing::ZoomFocus temp_focus = zoom_focus;
1695 zoom_focus = Editing::ZoomFocusMouse;
1696 temporal_zoom_step (coarser);
1697 zoom_focus = temp_focus;
1701 Editor::temporal_zoom_step (bool coarser)
1703 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1705 framecnt_t nspp = samples_per_pixel;
1713 temporal_zoom (nspp);
1717 Editor::temporal_zoom (framecnt_t fpp)
1723 framepos_t current_page = current_page_samples();
1724 framepos_t current_leftmost = leftmost_frame;
1725 framepos_t current_rightmost;
1726 framepos_t current_center;
1727 framepos_t new_page_size;
1728 framepos_t half_page_size;
1729 framepos_t leftmost_after_zoom = 0;
1731 bool in_track_canvas;
1735 if (fpp == samples_per_pixel) {
1739 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1740 // segfaults for lack of memory. If somebody decides this is not high enough I
1741 // believe it can be raisen to higher values but some limit must be in place.
1743 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1744 // all of which is used for the editor track displays. The whole day
1745 // would be 4147200000 samples, so 2592000 samples per pixel.
1747 nfpp = min (fpp, (framecnt_t) 2592000);
1748 nfpp = max ((framecnt_t) 1, nfpp);
1750 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1751 half_page_size = new_page_size / 2;
1753 switch (zoom_focus) {
1755 leftmost_after_zoom = current_leftmost;
1758 case ZoomFocusRight:
1759 current_rightmost = leftmost_frame + current_page;
1760 if (current_rightmost < new_page_size) {
1761 leftmost_after_zoom = 0;
1763 leftmost_after_zoom = current_rightmost - new_page_size;
1767 case ZoomFocusCenter:
1768 current_center = current_leftmost + (current_page/2);
1769 if (current_center < half_page_size) {
1770 leftmost_after_zoom = 0;
1772 leftmost_after_zoom = current_center - half_page_size;
1776 case ZoomFocusPlayhead:
1777 /* centre playhead */
1778 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1781 leftmost_after_zoom = 0;
1782 } else if (l > max_framepos) {
1783 leftmost_after_zoom = max_framepos - new_page_size;
1785 leftmost_after_zoom = (framepos_t) l;
1789 case ZoomFocusMouse:
1790 /* try to keep the mouse over the same point in the display */
1792 if (!mouse_frame (where, in_track_canvas)) {
1793 /* use playhead instead */
1794 where = playhead_cursor->current_frame ();
1796 if (where < half_page_size) {
1797 leftmost_after_zoom = 0;
1799 leftmost_after_zoom = where - half_page_size;
1804 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1807 leftmost_after_zoom = 0;
1808 } else if (l > max_framepos) {
1809 leftmost_after_zoom = max_framepos - new_page_size;
1811 leftmost_after_zoom = (framepos_t) l;
1818 /* try to keep the edit point in the same place */
1819 where = get_preferred_edit_position ();
1823 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1826 leftmost_after_zoom = 0;
1827 } else if (l > max_framepos) {
1828 leftmost_after_zoom = max_framepos - new_page_size;
1830 leftmost_after_zoom = (framepos_t) l;
1834 /* edit point not defined */
1841 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1843 reposition_and_zoom (leftmost_after_zoom, nfpp);
1847 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1849 /* this func helps make sure we leave a little space
1850 at each end of the editor so that the zoom doesn't fit the region
1851 precisely to the screen.
1854 GdkScreen* screen = gdk_screen_get_default ();
1855 const gint pixwidth = gdk_screen_get_width (screen);
1856 const gint mmwidth = gdk_screen_get_width_mm (screen);
1857 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1858 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1860 const framepos_t range = end - start;
1861 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1862 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1864 if (start > extra_samples) {
1865 start -= extra_samples;
1870 if (max_framepos - extra_samples > end) {
1871 end += extra_samples;
1878 Editor::temporal_zoom_region (bool both_axes)
1880 framepos_t start = max_framepos;
1882 set<TimeAxisView*> tracks;
1884 if ( !get_selection_extents(start, end) )
1887 calc_extra_zoom_edges (start, end);
1889 /* if we're zooming on both axes we need to save track heights etc.
1892 undo_visual_stack.push_back (current_visual_state (both_axes));
1894 PBD::Unwinder<bool> nsv (no_save_visual, true);
1896 temporal_zoom_by_frame (start, end);
1899 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1901 /* set visible track heights appropriately */
1903 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1904 (*t)->set_height (per_track_height);
1907 /* hide irrelevant tracks */
1909 DisplaySuspender ds;
1911 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1912 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1913 hide_track_in_display (*i);
1917 vertical_adjustment.set_value (0.0);
1920 redo_visual_stack.push_back (current_visual_state (both_axes));
1925 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1927 start = max_framepos;
1931 //ToDo: if notes are selected, set extents to that selection
1933 //ToDo: if control points are selected, set extents to that selection
1935 if ( !selection->regions.empty() ) {
1936 RegionSelection rs = get_regions_from_selection_and_entered ();
1938 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1940 if ((*i)->region()->position() < start) {
1941 start = (*i)->region()->position();
1944 if ((*i)->region()->last_frame() + 1 > end) {
1945 end = (*i)->region()->last_frame() + 1;
1949 } else if (!selection->time.empty()) {
1950 start = selection->time.start();
1951 end = selection->time.end_frame();
1953 ret = false; //no selection found
1956 if ((start == 0 && end == 0) || end < start) {
1965 Editor::temporal_zoom_selection (bool both_axes)
1967 if (!selection) return;
1969 //ToDo: if notes are selected, zoom to that
1971 //ToDo: if control points are selected, zoom to that
1973 //if region(s) are selected, zoom to that
1974 if ( !selection->regions.empty() )
1975 temporal_zoom_region (both_axes);
1977 //if a range is selected, zoom to that
1978 if (!selection->time.empty()) {
1980 framepos_t start, end;
1981 if (get_selection_extents (start, end)) {
1982 calc_extra_zoom_edges(start, end);
1983 temporal_zoom_by_frame (start, end);
1993 Editor::temporal_zoom_session ()
1995 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1998 framecnt_t start = _session->current_start_frame();
1999 framecnt_t end = _session->current_end_frame();
2001 if (_session->actively_recording () ) {
2002 framepos_t cur = playhead_cursor->current_frame ();
2004 /* recording beyond the end marker; zoom out
2005 * by 5 seconds more so that if 'follow
2006 * playhead' is active we don't immediately
2009 end = cur + _session->frame_rate() * 5;
2013 if ((start == 0 && end == 0) || end < start) {
2017 calc_extra_zoom_edges(start, end);
2019 temporal_zoom_by_frame (start, end);
2024 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2026 if (!_session) return;
2028 if ((start == 0 && end == 0) || end < start) {
2032 framepos_t range = end - start;
2034 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2036 framepos_t new_page = range;
2037 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2038 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2040 if (new_leftmost > middle) {
2044 if (new_leftmost < 0) {
2048 reposition_and_zoom (new_leftmost, new_fpp);
2052 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2058 framecnt_t range_before = frame - leftmost_frame;
2062 if (samples_per_pixel <= 1) {
2065 new_spp = samples_per_pixel + (samples_per_pixel/2);
2067 range_before += range_before/2;
2069 if (samples_per_pixel >= 1) {
2070 new_spp = samples_per_pixel - (samples_per_pixel/2);
2072 /* could bail out here since we cannot zoom any finer,
2073 but leave that to the equality test below
2075 new_spp = samples_per_pixel;
2078 range_before -= range_before/2;
2081 if (new_spp == samples_per_pixel) {
2085 /* zoom focus is automatically taken as @param frame when this
2089 framepos_t new_leftmost = frame - (framepos_t)range_before;
2091 if (new_leftmost > frame) {
2095 if (new_leftmost < 0) {
2099 reposition_and_zoom (new_leftmost, new_spp);
2104 Editor::choose_new_marker_name(string &name) {
2106 if (!UIConfiguration::instance().get_name_new_markers()) {
2107 /* don't prompt user for a new name */
2111 ArdourPrompter dialog (true);
2113 dialog.set_prompt (_("New Name:"));
2115 dialog.set_title (_("New Location Marker"));
2117 dialog.set_name ("MarkNameWindow");
2118 dialog.set_size_request (250, -1);
2119 dialog.set_position (Gtk::WIN_POS_MOUSE);
2121 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2122 dialog.set_initial_text (name);
2126 switch (dialog.run ()) {
2127 case RESPONSE_ACCEPT:
2133 dialog.get_result(name);
2140 Editor::add_location_from_selection ()
2144 if (selection->time.empty()) {
2148 if (_session == 0 || clicked_axisview == 0) {
2152 framepos_t start = selection->time[clicked_selection].start;
2153 framepos_t end = selection->time[clicked_selection].end;
2155 _session->locations()->next_available_name(rangename,"selection");
2156 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2158 begin_reversible_command (_("add marker"));
2160 XMLNode &before = _session->locations()->get_state();
2161 _session->locations()->add (location, true);
2162 XMLNode &after = _session->locations()->get_state();
2163 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2165 commit_reversible_command ();
2169 Editor::add_location_mark (framepos_t where)
2173 select_new_marker = true;
2175 _session->locations()->next_available_name(markername,"mark");
2176 if (!choose_new_marker_name(markername)) {
2179 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2180 begin_reversible_command (_("add marker"));
2182 XMLNode &before = _session->locations()->get_state();
2183 _session->locations()->add (location, true);
2184 XMLNode &after = _session->locations()->get_state();
2185 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2187 commit_reversible_command ();
2191 Editor::set_session_start_from_playhead ()
2197 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2198 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2200 XMLNode &before = loc->get_state();
2202 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2204 XMLNode &after = loc->get_state();
2206 begin_reversible_command (_("Set session start"));
2208 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2210 commit_reversible_command ();
2215 Editor::set_session_end_from_playhead ()
2221 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2222 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2224 XMLNode &before = loc->get_state();
2226 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2228 XMLNode &after = loc->get_state();
2230 begin_reversible_command (_("Set session start"));
2232 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2234 commit_reversible_command ();
2239 Editor::add_location_from_playhead_cursor ()
2241 add_location_mark (_session->audible_frame());
2245 Editor::remove_location_at_playhead_cursor ()
2249 XMLNode &before = _session->locations()->get_state();
2250 bool removed = false;
2252 //find location(s) at this time
2253 Locations::LocationList locs;
2254 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2255 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2256 if ((*i)->is_mark()) {
2257 _session->locations()->remove (*i);
2264 begin_reversible_command (_("remove marker"));
2265 XMLNode &after = _session->locations()->get_state();
2266 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2267 commit_reversible_command ();
2272 /** Add a range marker around each selected region */
2274 Editor::add_locations_from_region ()
2276 RegionSelection rs = get_regions_from_selection_and_entered ();
2281 bool commit = false;
2283 XMLNode &before = _session->locations()->get_state();
2285 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2287 boost::shared_ptr<Region> region = (*i)->region ();
2289 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2291 _session->locations()->add (location, true);
2296 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2297 XMLNode &after = _session->locations()->get_state();
2298 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2299 commit_reversible_command ();
2303 /** Add a single range marker around all selected regions */
2305 Editor::add_location_from_region ()
2307 RegionSelection rs = get_regions_from_selection_and_entered ();
2313 XMLNode &before = _session->locations()->get_state();
2317 if (rs.size() > 1) {
2318 _session->locations()->next_available_name(markername, "regions");
2320 RegionView* rv = *(rs.begin());
2321 boost::shared_ptr<Region> region = rv->region();
2322 markername = region->name();
2325 if (!choose_new_marker_name(markername)) {
2329 // single range spanning all selected
2330 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2331 _session->locations()->add (location, true);
2333 begin_reversible_command (_("add marker"));
2334 XMLNode &after = _session->locations()->get_state();
2335 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2336 commit_reversible_command ();
2342 Editor::jump_forward_to_mark ()
2348 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2354 _session->request_locate (pos, _session->transport_rolling());
2358 Editor::jump_backward_to_mark ()
2364 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2370 _session->request_locate (pos, _session->transport_rolling());
2376 framepos_t const pos = _session->audible_frame ();
2379 _session->locations()->next_available_name (markername, "mark");
2381 if (!choose_new_marker_name (markername)) {
2385 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2389 Editor::clear_markers ()
2392 begin_reversible_command (_("clear markers"));
2394 XMLNode &before = _session->locations()->get_state();
2395 _session->locations()->clear_markers ();
2396 XMLNode &after = _session->locations()->get_state();
2397 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2399 commit_reversible_command ();
2404 Editor::clear_ranges ()
2407 begin_reversible_command (_("clear ranges"));
2409 XMLNode &before = _session->locations()->get_state();
2411 _session->locations()->clear_ranges ();
2413 XMLNode &after = _session->locations()->get_state();
2414 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2416 commit_reversible_command ();
2421 Editor::clear_locations ()
2423 begin_reversible_command (_("clear locations"));
2425 XMLNode &before = _session->locations()->get_state();
2426 _session->locations()->clear ();
2427 XMLNode &after = _session->locations()->get_state();
2428 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2430 commit_reversible_command ();
2434 Editor::unhide_markers ()
2436 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2437 Location *l = (*i).first;
2438 if (l->is_hidden() && l->is_mark()) {
2439 l->set_hidden(false, this);
2445 Editor::unhide_ranges ()
2447 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2448 Location *l = (*i).first;
2449 if (l->is_hidden() && l->is_range_marker()) {
2450 l->set_hidden(false, this);
2455 /* INSERT/REPLACE */
2458 Editor::insert_region_list_selection (float times)
2460 RouteTimeAxisView *tv = 0;
2461 boost::shared_ptr<Playlist> playlist;
2463 if (clicked_routeview != 0) {
2464 tv = clicked_routeview;
2465 } else if (!selection->tracks.empty()) {
2466 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2469 } else if (entered_track != 0) {
2470 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2477 if ((playlist = tv->playlist()) == 0) {
2481 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2486 begin_reversible_command (_("insert region"));
2487 playlist->clear_changes ();
2488 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2489 if (Config->get_edit_mode() == Ripple)
2490 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2492 _session->add_command(new StatefulDiffCommand (playlist));
2493 commit_reversible_command ();
2496 /* BUILT-IN EFFECTS */
2499 Editor::reverse_selection ()
2504 /* GAIN ENVELOPE EDITING */
2507 Editor::edit_envelope ()
2514 Editor::transition_to_rolling (bool fwd)
2520 if (_session->config.get_external_sync()) {
2521 switch (Config->get_sync_source()) {
2525 /* transport controlled by the master */
2530 if (_session->is_auditioning()) {
2531 _session->cancel_audition ();
2535 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2539 Editor::play_from_start ()
2541 _session->request_locate (_session->current_start_frame(), true);
2545 Editor::play_from_edit_point ()
2547 _session->request_locate (get_preferred_edit_position(), true);
2551 Editor::play_from_edit_point_and_return ()
2553 framepos_t start_frame;
2554 framepos_t return_frame;
2556 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2558 if (_session->transport_rolling()) {
2559 _session->request_locate (start_frame, false);
2563 /* don't reset the return frame if its already set */
2565 if ((return_frame = _session->requested_return_frame()) < 0) {
2566 return_frame = _session->audible_frame();
2569 if (start_frame >= 0) {
2570 _session->request_roll_at_and_return (start_frame, return_frame);
2575 Editor::play_selection ()
2577 framepos_t start, end;
2578 if (!get_selection_extents ( start, end))
2581 AudioRange ar (start, end, 0);
2582 list<AudioRange> lar;
2585 _session->request_play_range (&lar, true);
2589 Editor::get_preroll ()
2591 return Config->get_preroll_seconds() * _session->frame_rate();
2596 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2598 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2601 location -= get_preroll();
2603 //don't try to locate before the beginning of time
2607 //if follow_playhead is on, keep the playhead on the screen
2608 if ( _follow_playhead )
2609 if ( location < leftmost_frame )
2610 location = leftmost_frame;
2612 _session->request_locate( location );
2616 Editor::play_with_preroll ()
2619 framepos_t preroll = get_preroll();
2621 framepos_t start, end;
2622 if (!get_selection_extents ( start, end))
2625 if (start > preroll)
2626 start = start - preroll;
2628 end = end + preroll; //"post-roll"
2630 AudioRange ar (start, end, 0);
2631 list<AudioRange> lar;
2634 _session->request_play_range (&lar, true);
2639 Editor::play_location (Location& location)
2641 if (location.start() <= location.end()) {
2645 _session->request_bounded_roll (location.start(), location.end());
2649 Editor::loop_location (Location& location)
2651 if (location.start() <= location.end()) {
2657 if ((tll = transport_loop_location()) != 0) {
2658 tll->set (location.start(), location.end());
2660 // enable looping, reposition and start rolling
2661 _session->request_locate (tll->start(), true);
2662 _session->request_play_loop (true);
2667 Editor::do_layer_operation (LayerOperation op)
2669 if (selection->regions.empty ()) {
2673 bool const multiple = selection->regions.size() > 1;
2677 begin_reversible_command (_("raise regions"));
2679 begin_reversible_command (_("raise region"));
2685 begin_reversible_command (_("raise regions to top"));
2687 begin_reversible_command (_("raise region to top"));
2693 begin_reversible_command (_("lower regions"));
2695 begin_reversible_command (_("lower region"));
2701 begin_reversible_command (_("lower regions to bottom"));
2703 begin_reversible_command (_("lower region"));
2708 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2709 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2710 (*i)->clear_owned_changes ();
2713 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2714 boost::shared_ptr<Region> r = (*i)->region ();
2726 r->lower_to_bottom ();
2730 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2731 vector<Command*> cmds;
2733 _session->add_commands (cmds);
2736 commit_reversible_command ();
2740 Editor::raise_region ()
2742 do_layer_operation (Raise);
2746 Editor::raise_region_to_top ()
2748 do_layer_operation (RaiseToTop);
2752 Editor::lower_region ()
2754 do_layer_operation (Lower);
2758 Editor::lower_region_to_bottom ()
2760 do_layer_operation (LowerToBottom);
2763 /** Show the region editor for the selected regions */
2765 Editor::show_region_properties ()
2767 selection->foreach_regionview (&RegionView::show_region_editor);
2770 /** Show the midi list editor for the selected MIDI regions */
2772 Editor::show_midi_list_editor ()
2774 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2778 Editor::rename_region ()
2780 RegionSelection rs = get_regions_from_selection_and_entered ();
2786 ArdourDialog d (_("Rename Region"), true, false);
2788 Label label (_("New name:"));
2791 hbox.set_spacing (6);
2792 hbox.pack_start (label, false, false);
2793 hbox.pack_start (entry, true, true);
2795 d.get_vbox()->set_border_width (12);
2796 d.get_vbox()->pack_start (hbox, false, false);
2798 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2799 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2801 d.set_size_request (300, -1);
2803 entry.set_text (rs.front()->region()->name());
2804 entry.select_region (0, -1);
2806 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2812 int const ret = d.run();
2816 if (ret != RESPONSE_OK) {
2820 std::string str = entry.get_text();
2821 strip_whitespace_edges (str);
2823 rs.front()->region()->set_name (str);
2824 _regions->redisplay ();
2828 /** Start an audition of the first selected region */
2830 Editor::play_edit_range ()
2832 framepos_t start, end;
2834 if (get_edit_op_range (start, end)) {
2835 _session->request_bounded_roll (start, end);
2840 Editor::play_selected_region ()
2842 framepos_t start = max_framepos;
2845 RegionSelection rs = get_regions_from_selection_and_entered ();
2851 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2852 if ((*i)->region()->position() < start) {
2853 start = (*i)->region()->position();
2855 if ((*i)->region()->last_frame() + 1 > end) {
2856 end = (*i)->region()->last_frame() + 1;
2860 _session->request_bounded_roll (start, end);
2864 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2866 _session->audition_region (region);
2870 Editor::region_from_selection ()
2872 if (clicked_axisview == 0) {
2876 if (selection->time.empty()) {
2880 framepos_t start = selection->time[clicked_selection].start;
2881 framepos_t end = selection->time[clicked_selection].end;
2883 TrackViewList tracks = get_tracks_for_range_action ();
2885 framepos_t selection_cnt = end - start + 1;
2887 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2888 boost::shared_ptr<Region> current;
2889 boost::shared_ptr<Playlist> pl;
2890 framepos_t internal_start;
2893 if ((pl = (*i)->playlist()) == 0) {
2897 if ((current = pl->top_region_at (start)) == 0) {
2901 internal_start = start - current->position();
2902 RegionFactory::region_name (new_name, current->name(), true);
2906 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2907 plist.add (ARDOUR::Properties::length, selection_cnt);
2908 plist.add (ARDOUR::Properties::name, new_name);
2909 plist.add (ARDOUR::Properties::layer, 0);
2911 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2916 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2918 if (selection->time.empty() || selection->tracks.empty()) {
2922 framepos_t start, end;
2923 if (clicked_selection) {
2924 start = selection->time[clicked_selection].start;
2925 end = selection->time[clicked_selection].end;
2927 start = selection->time.start();
2928 end = selection->time.end_frame();
2931 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2932 sort_track_selection (ts);
2934 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2935 boost::shared_ptr<Region> current;
2936 boost::shared_ptr<Playlist> playlist;
2937 framepos_t internal_start;
2940 if ((playlist = (*i)->playlist()) == 0) {
2944 if ((current = playlist->top_region_at(start)) == 0) {
2948 internal_start = start - current->position();
2949 RegionFactory::region_name (new_name, current->name(), true);
2953 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2954 plist.add (ARDOUR::Properties::length, end - start + 1);
2955 plist.add (ARDOUR::Properties::name, new_name);
2957 new_regions.push_back (RegionFactory::create (current, plist));
2962 Editor::split_multichannel_region ()
2964 RegionSelection rs = get_regions_from_selection_and_entered ();
2970 vector< boost::shared_ptr<Region> > v;
2972 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2973 (*x)->region()->separate_by_channel (*_session, v);
2978 Editor::new_region_from_selection ()
2980 region_from_selection ();
2981 cancel_selection ();
2985 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2987 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2988 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2989 case Evoral::OverlapNone:
2997 * - selected tracks, or if there are none...
2998 * - tracks containing selected regions, or if there are none...
3003 Editor::get_tracks_for_range_action () const
3007 if (selection->tracks.empty()) {
3009 /* use tracks with selected regions */
3011 RegionSelection rs = selection->regions;
3013 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3014 TimeAxisView* tv = &(*i)->get_time_axis_view();
3016 if (!t.contains (tv)) {
3022 /* no regions and no tracks: use all tracks */
3028 t = selection->tracks;
3031 return t.filter_to_unique_playlists();
3035 Editor::separate_regions_between (const TimeSelection& ts)
3037 bool in_command = false;
3038 boost::shared_ptr<Playlist> playlist;
3039 RegionSelection new_selection;
3041 TrackViewList tmptracks = get_tracks_for_range_action ();
3042 sort_track_selection (tmptracks);
3044 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3046 RouteTimeAxisView* rtv;
3048 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3050 if (rtv->is_track()) {
3052 /* no edits to destructive tracks */
3054 if (rtv->track()->destructive()) {
3058 if ((playlist = rtv->playlist()) != 0) {
3060 playlist->clear_changes ();
3062 /* XXX need to consider musical time selections here at some point */
3064 double speed = rtv->track()->speed();
3067 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3069 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3070 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3072 latest_regionviews.clear ();
3074 playlist->partition ((framepos_t)((*t).start * speed),
3075 (framepos_t)((*t).end * speed), false);
3079 if (!latest_regionviews.empty()) {
3081 rtv->view()->foreach_regionview (sigc::bind (
3082 sigc::ptr_fun (add_if_covered),
3083 &(*t), &new_selection));
3086 begin_reversible_command (_("separate"));
3090 /* pick up changes to existing regions */
3092 vector<Command*> cmds;
3093 playlist->rdiff (cmds);
3094 _session->add_commands (cmds);
3096 /* pick up changes to the playlist itself (adds/removes)
3099 _session->add_command(new StatefulDiffCommand (playlist));
3108 // selection->set (new_selection);
3110 commit_reversible_command ();
3114 struct PlaylistState {
3115 boost::shared_ptr<Playlist> playlist;
3119 /** Take tracks from get_tracks_for_range_action and cut any regions
3120 * on those tracks so that the tracks are empty over the time
3124 Editor::separate_region_from_selection ()
3126 /* preferentially use *all* ranges in the time selection if we're in range mode
3127 to allow discontiguous operation, since get_edit_op_range() currently
3128 returns a single range.
3131 if (!selection->time.empty()) {
3133 separate_regions_between (selection->time);
3140 if (get_edit_op_range (start, end)) {
3142 AudioRange ar (start, end, 1);
3146 separate_regions_between (ts);
3152 Editor::separate_region_from_punch ()
3154 Location* loc = _session->locations()->auto_punch_location();
3156 separate_regions_using_location (*loc);
3161 Editor::separate_region_from_loop ()
3163 Location* loc = _session->locations()->auto_loop_location();
3165 separate_regions_using_location (*loc);
3170 Editor::separate_regions_using_location (Location& loc)
3172 if (loc.is_mark()) {
3176 AudioRange ar (loc.start(), loc.end(), 1);
3181 separate_regions_between (ts);
3184 /** Separate regions under the selected region */
3186 Editor::separate_under_selected_regions ()
3188 vector<PlaylistState> playlists;
3192 rs = get_regions_from_selection_and_entered();
3194 if (!_session || rs.empty()) {
3198 begin_reversible_command (_("separate region under"));
3200 list<boost::shared_ptr<Region> > regions_to_remove;
3202 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3203 // we can't just remove the region(s) in this loop because
3204 // this removes them from the RegionSelection, and they thus
3205 // disappear from underneath the iterator, and the ++i above
3206 // SEGVs in a puzzling fashion.
3208 // so, first iterate over the regions to be removed from rs and
3209 // add them to the regions_to_remove list, and then
3210 // iterate over the list to actually remove them.
3212 regions_to_remove.push_back ((*i)->region());
3215 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3217 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3220 // is this check necessary?
3224 vector<PlaylistState>::iterator i;
3226 //only take state if this is a new playlist.
3227 for (i = playlists.begin(); i != playlists.end(); ++i) {
3228 if ((*i).playlist == playlist) {
3233 if (i == playlists.end()) {
3235 PlaylistState before;
3236 before.playlist = playlist;
3237 before.before = &playlist->get_state();
3239 playlist->freeze ();
3240 playlists.push_back(before);
3243 //Partition on the region bounds
3244 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3246 //Re-add region that was just removed due to the partition operation
3247 playlist->add_region( (*rl), (*rl)->first_frame() );
3250 vector<PlaylistState>::iterator pl;
3252 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3253 (*pl).playlist->thaw ();
3254 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3257 commit_reversible_command ();
3261 Editor::crop_region_to_selection ()
3263 if (!selection->time.empty()) {
3265 crop_region_to (selection->time.start(), selection->time.end_frame());
3272 if (get_edit_op_range (start, end)) {
3273 crop_region_to (start, end);
3280 Editor::crop_region_to (framepos_t start, framepos_t end)
3282 vector<boost::shared_ptr<Playlist> > playlists;
3283 boost::shared_ptr<Playlist> playlist;
3286 if (selection->tracks.empty()) {
3287 ts = track_views.filter_to_unique_playlists();
3289 ts = selection->tracks.filter_to_unique_playlists ();
3292 sort_track_selection (ts);
3294 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3296 RouteTimeAxisView* rtv;
3298 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3300 boost::shared_ptr<Track> t = rtv->track();
3302 if (t != 0 && ! t->destructive()) {
3304 if ((playlist = rtv->playlist()) != 0) {
3305 playlists.push_back (playlist);
3311 if (playlists.empty()) {
3316 framepos_t new_start;
3318 framecnt_t new_length;
3319 bool in_command = false;
3321 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3323 /* Only the top regions at start and end have to be cropped */
3324 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3325 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3327 vector<boost::shared_ptr<Region> > regions;
3329 if (region_at_start != 0) {
3330 regions.push_back (region_at_start);
3332 if (region_at_end != 0) {
3333 regions.push_back (region_at_end);
3336 /* now adjust lengths */
3337 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3339 pos = (*i)->position();
3340 new_start = max (start, pos);
3341 if (max_framepos - pos > (*i)->length()) {
3342 new_end = pos + (*i)->length() - 1;
3344 new_end = max_framepos;
3346 new_end = min (end, new_end);
3347 new_length = new_end - new_start + 1;
3350 begin_reversible_command (_("trim to selection"));
3353 (*i)->clear_changes ();
3354 (*i)->trim_to (new_start, new_length);
3355 _session->add_command (new StatefulDiffCommand (*i));
3360 commit_reversible_command ();
3365 Editor::region_fill_track ()
3367 boost::shared_ptr<Playlist> playlist;
3368 RegionSelection regions = get_regions_from_selection_and_entered ();
3369 RegionSelection foo;
3371 framepos_t const end = _session->current_end_frame ();
3373 if (regions.empty () || regions.end_frame () + 1 >= end) {
3377 framepos_t const start_frame = regions.start ();
3378 framepos_t const end_frame = regions.end_frame ();
3379 framecnt_t const gap = end_frame - start_frame + 1;
3381 begin_reversible_command (Operations::region_fill);
3383 selection->clear_regions ();
3385 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3387 boost::shared_ptr<Region> r ((*i)->region());
3389 TimeAxisView& tv = (*i)->get_time_axis_view();
3390 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3391 latest_regionviews.clear ();
3392 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3394 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3395 playlist = (*i)->region()->playlist();
3396 playlist->clear_changes ();
3397 playlist->duplicate_until (r, position, gap, end);
3398 _session->add_command(new StatefulDiffCommand (playlist));
3402 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3406 selection->set (foo);
3409 commit_reversible_command ();
3413 Editor::set_region_sync_position ()
3415 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3419 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3421 bool in_command = false;
3423 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3425 if (!(*r)->region()->covers (where)) {
3429 boost::shared_ptr<Region> region ((*r)->region());
3432 begin_reversible_command (_("set sync point"));
3436 region->clear_changes ();
3437 region->set_sync_position (where);
3438 _session->add_command(new StatefulDiffCommand (region));
3442 commit_reversible_command ();
3446 /** Remove the sync positions of the selection */
3448 Editor::remove_region_sync ()
3450 RegionSelection rs = get_regions_from_selection_and_entered ();
3456 begin_reversible_command (_("remove region sync"));
3458 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3460 (*i)->region()->clear_changes ();
3461 (*i)->region()->clear_sync_position ();
3462 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3465 commit_reversible_command ();
3469 Editor::naturalize_region ()
3471 RegionSelection rs = get_regions_from_selection_and_entered ();
3477 if (rs.size() > 1) {
3478 begin_reversible_command (_("move regions to original position"));
3480 begin_reversible_command (_("move region to original position"));
3483 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3484 (*i)->region()->clear_changes ();
3485 (*i)->region()->move_to_natural_position ();
3486 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3489 commit_reversible_command ();
3493 Editor::align_regions (RegionPoint what)
3495 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3501 begin_reversible_command (_("align selection"));
3503 framepos_t const position = get_preferred_edit_position ();
3505 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3506 align_region_internal ((*i)->region(), what, position);
3509 commit_reversible_command ();
3512 struct RegionSortByTime {
3513 bool operator() (const RegionView* a, const RegionView* b) {
3514 return a->region()->position() < b->region()->position();
3519 Editor::align_regions_relative (RegionPoint point)
3521 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3527 framepos_t const position = get_preferred_edit_position ();
3529 framepos_t distance = 0;
3533 list<RegionView*> sorted;
3534 rs.by_position (sorted);
3536 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3541 if (position > r->position()) {
3542 distance = position - r->position();
3544 distance = r->position() - position;
3550 if (position > r->last_frame()) {
3551 distance = position - r->last_frame();
3552 pos = r->position() + distance;
3554 distance = r->last_frame() - position;
3555 pos = r->position() - distance;
3561 pos = r->adjust_to_sync (position);
3562 if (pos > r->position()) {
3563 distance = pos - r->position();
3565 distance = r->position() - pos;
3571 if (pos == r->position()) {
3575 begin_reversible_command (_("align selection (relative)"));
3577 /* move first one specially */
3579 r->clear_changes ();
3580 r->set_position (pos);
3581 _session->add_command(new StatefulDiffCommand (r));
3583 /* move rest by the same amount */
3587 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3589 boost::shared_ptr<Region> region ((*i)->region());
3591 region->clear_changes ();
3594 region->set_position (region->position() + distance);
3596 region->set_position (region->position() - distance);
3599 _session->add_command(new StatefulDiffCommand (region));
3603 commit_reversible_command ();
3607 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3609 begin_reversible_command (_("align region"));
3610 align_region_internal (region, point, position);
3611 commit_reversible_command ();
3615 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3617 region->clear_changes ();
3621 region->set_position (region->adjust_to_sync (position));
3625 if (position > region->length()) {
3626 region->set_position (position - region->length());
3631 region->set_position (position);
3635 _session->add_command(new StatefulDiffCommand (region));
3639 Editor::trim_region_front ()
3645 Editor::trim_region_back ()
3647 trim_region (false);
3651 Editor::trim_region (bool front)
3653 framepos_t where = get_preferred_edit_position();
3654 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3660 begin_reversible_command (front ? _("trim front") : _("trim back"));
3662 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3663 if (!(*i)->region()->locked()) {
3665 (*i)->region()->clear_changes ();
3668 (*i)->region()->trim_front (where);
3669 maybe_locate_with_edit_preroll ( where );
3671 (*i)->region()->trim_end (where);
3672 maybe_locate_with_edit_preroll ( where );
3675 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3679 commit_reversible_command ();
3682 /** Trim the end of the selected regions to the position of the edit cursor */
3684 Editor::trim_region_to_loop ()
3686 Location* loc = _session->locations()->auto_loop_location();
3690 trim_region_to_location (*loc, _("trim to loop"));
3694 Editor::trim_region_to_punch ()
3696 Location* loc = _session->locations()->auto_punch_location();
3700 trim_region_to_location (*loc, _("trim to punch"));
3704 Editor::trim_region_to_location (const Location& loc, const char* str)
3706 RegionSelection rs = get_regions_from_selection_and_entered ();
3707 bool in_command = false;
3709 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3710 RegionView* rv = (*x);
3712 /* require region to span proposed trim */
3713 switch (rv->region()->coverage (loc.start(), loc.end())) {
3714 case Evoral::OverlapInternal:
3720 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3729 if (tav->track() != 0) {
3730 speed = tav->track()->speed();
3733 start = session_frame_to_track_frame (loc.start(), speed);
3734 end = session_frame_to_track_frame (loc.end(), speed);
3736 rv->region()->clear_changes ();
3737 rv->region()->trim_to (start, (end - start));
3740 begin_reversible_command (str);
3743 _session->add_command(new StatefulDiffCommand (rv->region()));
3747 commit_reversible_command ();
3752 Editor::trim_region_to_previous_region_end ()
3754 return trim_to_region(false);
3758 Editor::trim_region_to_next_region_start ()
3760 return trim_to_region(true);
3764 Editor::trim_to_region(bool forward)
3766 RegionSelection rs = get_regions_from_selection_and_entered ();
3767 bool in_command = false;
3769 boost::shared_ptr<Region> next_region;
3771 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3773 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3779 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3787 if (atav->track() != 0) {
3788 speed = atav->track()->speed();
3792 boost::shared_ptr<Region> region = arv->region();
3793 boost::shared_ptr<Playlist> playlist (region->playlist());
3795 region->clear_changes ();
3799 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3805 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3806 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3810 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3816 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3818 arv->region_changed (ARDOUR::bounds_change);
3822 begin_reversible_command (_("trim to region"));
3825 _session->add_command(new StatefulDiffCommand (region));
3829 commit_reversible_command ();
3834 Editor::unfreeze_route ()
3836 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3840 clicked_routeview->track()->unfreeze ();
3844 Editor::_freeze_thread (void* arg)
3846 return static_cast<Editor*>(arg)->freeze_thread ();
3850 Editor::freeze_thread ()
3852 /* create event pool because we may need to talk to the session */
3853 SessionEvent::create_per_thread_pool ("freeze events", 64);
3854 /* create per-thread buffers for process() tree to use */
3855 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3856 current_interthread_info->done = true;
3861 Editor::freeze_route ()
3867 /* stop transport before we start. this is important */
3869 _session->request_transport_speed (0.0);
3871 /* wait for just a little while, because the above call is asynchronous */
3873 Glib::usleep (250000);
3875 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3879 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3881 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3882 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3884 d.set_title (_("Cannot freeze"));
3889 if (clicked_routeview->track()->has_external_redirects()) {
3890 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"
3891 "Freezing will only process the signal as far as the first send/insert/return."),
3892 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3894 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3895 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3896 d.set_title (_("Freeze Limits"));
3898 int response = d.run ();
3901 case Gtk::RESPONSE_CANCEL:
3908 InterThreadInfo itt;
3909 current_interthread_info = &itt;
3911 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3913 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3915 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3917 while (!itt.done && !itt.cancel) {
3918 gtk_main_iteration ();
3921 pthread_join (itt.thread, 0);
3922 current_interthread_info = 0;
3926 Editor::bounce_range_selection (bool replace, bool enable_processing)
3928 if (selection->time.empty()) {
3932 TrackSelection views = selection->tracks;
3934 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3936 if (enable_processing) {
3938 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3940 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3942 _("You can't perform this operation because the processing of the signal "
3943 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3944 "You can do this without processing, which is a different operation.")
3946 d.set_title (_("Cannot bounce"));
3953 framepos_t start = selection->time[clicked_selection].start;
3954 framepos_t end = selection->time[clicked_selection].end;
3955 framepos_t cnt = end - start + 1;
3956 bool in_command = false;
3958 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3960 RouteTimeAxisView* rtv;
3962 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3966 boost::shared_ptr<Playlist> playlist;
3968 if ((playlist = rtv->playlist()) == 0) {
3972 InterThreadInfo itt;
3974 playlist->clear_changes ();
3975 playlist->clear_owned_changes ();
3977 boost::shared_ptr<Region> r;
3979 if (enable_processing) {
3980 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3982 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3990 list<AudioRange> ranges;
3991 ranges.push_back (AudioRange (start, start+cnt, 0));
3992 playlist->cut (ranges); // discard result
3993 playlist->add_region (r, start);
3997 begin_reversible_command (_("bounce range"));
4000 vector<Command*> cmds;
4001 playlist->rdiff (cmds);
4002 _session->add_commands (cmds);
4004 _session->add_command (new StatefulDiffCommand (playlist));
4008 commit_reversible_command ();
4012 /** Delete selected regions, automation points or a time range */
4016 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4017 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4018 bool deleted = false;
4019 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4020 deleted = current_mixer_strip->delete_processors ();
4026 /** Cut selected regions, automation points or a time range */
4033 /** Copy selected regions, automation points or a time range */
4041 /** @return true if a Cut, Copy or Clear is possible */
4043 Editor::can_cut_copy () const
4045 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4052 /** Cut, copy or clear selected regions, automation points or a time range.
4053 * @param op Operation (Delete, Cut, Copy or Clear)
4056 Editor::cut_copy (CutCopyOp op)
4058 /* only cancel selection if cut/copy is successful.*/
4064 opname = _("delete");
4073 opname = _("clear");
4077 /* if we're deleting something, and the mouse is still pressed,
4078 the thing we started a drag for will be gone when we release
4079 the mouse button(s). avoid this. see part 2 at the end of
4083 if (op == Delete || op == Cut || op == Clear) {
4084 if (_drags->active ()) {
4089 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4090 cut_buffer->clear ();
4092 if (entered_marker) {
4094 /* cut/delete op while pointing at a marker */
4097 Location* loc = find_location_from_marker (entered_marker, ignored);
4099 if (_session && loc) {
4100 entered_marker = NULL;
4101 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4108 switch (mouse_mode) {
4111 begin_reversible_command (opname + ' ' + X_("MIDI"));
4113 commit_reversible_command ();
4119 bool did_edit = false;
4121 if (!selection->regions.empty() || !selection->points.empty()) {
4122 begin_reversible_command (opname + ' ' + _("objects"));
4125 if (!selection->regions.empty()) {
4126 cut_copy_regions (op, selection->regions);
4128 if (op == Cut || op == Delete) {
4129 selection->clear_regions ();
4133 if (!selection->points.empty()) {
4134 cut_copy_points (op);
4136 if (op == Cut || op == Delete) {
4137 selection->clear_points ();
4140 } else if (selection->time.empty()) {
4141 framepos_t start, end;
4142 /* no time selection, see if we can get an edit range
4145 if (get_edit_op_range (start, end)) {
4146 selection->set (start, end);
4148 } else if (!selection->time.empty()) {
4149 begin_reversible_command (opname + ' ' + _("range"));
4152 cut_copy_ranges (op);
4154 if (op == Cut || op == Delete) {
4155 selection->clear_time ();
4160 /* reset repeated paste state */
4163 commit_reversible_command ();
4166 if (op == Delete || op == Cut || op == Clear) {
4171 struct AutomationRecord {
4172 AutomationRecord () : state (0) , line(NULL) {}
4173 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4175 XMLNode* state; ///< state before any operation
4176 const AutomationLine* line; ///< line this came from
4177 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4180 /** Cut, copy or clear selected automation points.
4181 * @param op Operation (Cut, Copy or Clear)
4184 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4186 if (selection->points.empty ()) {
4190 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4191 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4193 /* Keep a record of the AutomationLists that we end up using in this operation */
4194 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4197 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4198 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4199 const AutomationLine& line = (*i)->line();
4200 const boost::shared_ptr<AutomationList> al = line.the_list();
4201 if (lists.find (al) == lists.end ()) {
4202 /* We haven't seen this list yet, so make a record for it. This includes
4203 taking a copy of its current state, in case this is needed for undo later.
4205 lists[al] = AutomationRecord (&al->get_state (), &line);
4209 if (op == Cut || op == Copy) {
4210 /* This operation will involve putting things in the cut buffer, so create an empty
4211 ControlList for each of our source lists to put the cut buffer data in.
4213 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4214 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4217 /* Add all selected points to the relevant copy ControlLists */
4218 framepos_t start = std::numeric_limits<framepos_t>::max();
4219 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4220 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4221 AutomationList::const_iterator j = (*i)->model();
4223 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4225 /* Update earliest MIDI start time in beats */
4226 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4228 /* Update earliest session start time in frames */
4229 start = std::min(start, (*i)->line().session_position(j));
4233 /* Snap start time backwards, so copy/paste is snap aligned. */
4235 if (earliest == Evoral::Beats::max()) {
4236 earliest = Evoral::Beats(); // Weird... don't offset
4238 earliest.round_down_to_beat();
4240 if (start == std::numeric_limits<double>::max()) {
4241 start = 0; // Weird... don't offset
4243 snap_to(start, RoundDownMaybe);
4246 const double line_offset = midi ? earliest.to_double() : start;
4247 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4248 /* Correct this copy list so that it is relative to the earliest
4249 start time, so relative ordering between points is preserved
4250 when copying from several lists and the paste starts at the
4251 earliest copied piece of data. */
4252 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4253 (*j)->when -= line_offset;
4256 /* And add it to the cut buffer */
4257 cut_buffer->add (i->second.copy);
4261 if (op == Delete || op == Cut) {
4262 /* This operation needs to remove things from the main AutomationList, so do that now */
4264 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4265 i->first->freeze ();
4268 /* Remove each selected point from its AutomationList */
4269 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4270 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4271 al->erase ((*i)->model ());
4274 /* Thaw the lists and add undo records for them */
4275 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4276 boost::shared_ptr<AutomationList> al = i->first;
4278 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4283 /** Cut, copy or clear selected automation points.
4284 * @param op Operation (Cut, Copy or Clear)
4287 Editor::cut_copy_midi (CutCopyOp op)
4289 Evoral::Beats earliest = Evoral::Beats::max();
4290 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4291 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4293 if (!mrv->selection().empty()) {
4294 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4296 mrv->cut_copy_clear (op);
4298 /* XXX: not ideal, as there may be more than one track involved in the selection */
4299 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4303 if (!selection->points.empty()) {
4304 cut_copy_points (op, earliest, true);
4305 if (op == Cut || op == Delete) {
4306 selection->clear_points ();
4311 struct lt_playlist {
4312 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4313 return a.playlist < b.playlist;
4317 struct PlaylistMapping {
4319 boost::shared_ptr<Playlist> pl;
4321 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4324 /** Remove `clicked_regionview' */
4326 Editor::remove_clicked_region ()
4328 if (clicked_routeview == 0 || clicked_regionview == 0) {
4332 begin_reversible_command (_("remove region"));
4334 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4336 playlist->clear_changes ();
4337 playlist->clear_owned_changes ();
4338 playlist->remove_region (clicked_regionview->region());
4339 if (Config->get_edit_mode() == Ripple)
4340 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4342 /* We might have removed regions, which alters other regions' layering_index,
4343 so we need to do a recursive diff here.
4345 vector<Command*> cmds;
4346 playlist->rdiff (cmds);
4347 _session->add_commands (cmds);
4349 _session->add_command(new StatefulDiffCommand (playlist));
4350 commit_reversible_command ();
4354 /** Remove the selected regions */
4356 Editor::remove_selected_regions ()
4358 RegionSelection rs = get_regions_from_selection_and_entered ();
4360 if (!_session || rs.empty()) {
4364 list<boost::shared_ptr<Region> > regions_to_remove;
4366 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4367 // we can't just remove the region(s) in this loop because
4368 // this removes them from the RegionSelection, and they thus
4369 // disappear from underneath the iterator, and the ++i above
4370 // SEGVs in a puzzling fashion.
4372 // so, first iterate over the regions to be removed from rs and
4373 // add them to the regions_to_remove list, and then
4374 // iterate over the list to actually remove them.
4376 regions_to_remove.push_back ((*i)->region());
4379 vector<boost::shared_ptr<Playlist> > playlists;
4381 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4383 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4386 // is this check necessary?
4390 /* get_regions_from_selection_and_entered() guarantees that
4391 the playlists involved are unique, so there is no need
4395 playlists.push_back (playlist);
4397 playlist->clear_changes ();
4398 playlist->clear_owned_changes ();
4399 playlist->freeze ();
4400 playlist->remove_region (*rl);
4401 if (Config->get_edit_mode() == Ripple)
4402 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4406 vector<boost::shared_ptr<Playlist> >::iterator pl;
4407 bool in_command = false;
4409 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4412 /* We might have removed regions, which alters other regions' layering_index,
4413 so we need to do a recursive diff here.
4417 begin_reversible_command (_("remove region"));
4420 vector<Command*> cmds;
4421 (*pl)->rdiff (cmds);
4422 _session->add_commands (cmds);
4424 _session->add_command(new StatefulDiffCommand (*pl));
4428 commit_reversible_command ();
4432 /** Cut, copy or clear selected regions.
4433 * @param op Operation (Cut, Copy or Clear)
4436 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4438 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4439 a map when we want ordered access to both elements. i think.
4442 vector<PlaylistMapping> pmap;
4444 framepos_t first_position = max_framepos;
4446 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4447 FreezeList freezelist;
4449 /* get ordering correct before we cut/copy */
4451 rs.sort_by_position_and_track ();
4453 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4455 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4457 if (op == Cut || op == Clear || op == Delete) {
4458 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4461 FreezeList::iterator fl;
4463 // only take state if this is a new playlist.
4464 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4470 if (fl == freezelist.end()) {
4471 pl->clear_changes();
4472 pl->clear_owned_changes ();
4474 freezelist.insert (pl);
4479 TimeAxisView* tv = &(*x)->get_time_axis_view();
4480 vector<PlaylistMapping>::iterator z;
4482 for (z = pmap.begin(); z != pmap.end(); ++z) {
4483 if ((*z).tv == tv) {
4488 if (z == pmap.end()) {
4489 pmap.push_back (PlaylistMapping (tv));
4493 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4495 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4498 /* region not yet associated with a playlist (e.g. unfinished
4505 TimeAxisView& tv = (*x)->get_time_axis_view();
4506 boost::shared_ptr<Playlist> npl;
4507 RegionSelection::iterator tmp;
4514 vector<PlaylistMapping>::iterator z;
4516 for (z = pmap.begin(); z != pmap.end(); ++z) {
4517 if ((*z).tv == &tv) {
4522 assert (z != pmap.end());
4525 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4533 boost::shared_ptr<Region> r = (*x)->region();
4534 boost::shared_ptr<Region> _xx;
4540 pl->remove_region (r);
4541 if (Config->get_edit_mode() == Ripple)
4542 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4546 _xx = RegionFactory::create (r);
4547 npl->add_region (_xx, r->position() - first_position);
4548 pl->remove_region (r);
4549 if (Config->get_edit_mode() == Ripple)
4550 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4554 /* copy region before adding, so we're not putting same object into two different playlists */
4555 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4559 pl->remove_region (r);
4560 if (Config->get_edit_mode() == Ripple)
4561 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4570 list<boost::shared_ptr<Playlist> > foo;
4572 /* the pmap is in the same order as the tracks in which selected regions occurred */
4574 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4577 foo.push_back ((*i).pl);
4582 cut_buffer->set (foo);
4586 _last_cut_copy_source_track = 0;
4588 _last_cut_copy_source_track = pmap.front().tv;
4592 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4595 /* We might have removed regions, which alters other regions' layering_index,
4596 so we need to do a recursive diff here.
4598 vector<Command*> cmds;
4599 (*pl)->rdiff (cmds);
4600 _session->add_commands (cmds);
4602 _session->add_command (new StatefulDiffCommand (*pl));
4607 Editor::cut_copy_ranges (CutCopyOp op)
4609 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4611 /* Sort the track selection now, so that it if is used, the playlists
4612 selected by the calls below to cut_copy_clear are in the order that
4613 their tracks appear in the editor. This makes things like paste
4614 of ranges work properly.
4617 sort_track_selection (ts);
4620 if (!entered_track) {
4623 ts.push_back (entered_track);
4626 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4627 (*i)->cut_copy_clear (*selection, op);
4632 Editor::paste (float times, bool from_context)
4634 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4636 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4640 Editor::mouse_paste ()
4645 if (!mouse_frame (where, ignored)) {
4650 paste_internal (where, 1);
4654 Editor::paste_internal (framepos_t position, float times)
4656 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4658 if (cut_buffer->empty(internal_editing())) {
4662 if (position == max_framepos) {
4663 position = get_preferred_edit_position();
4664 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4667 if (position == last_paste_pos) {
4668 /* repeated paste in the same position */
4671 /* paste in new location, reset repeated paste state */
4673 last_paste_pos = position;
4676 /* get everything in the correct order */
4679 if (!selection->tracks.empty()) {
4680 /* If there is a track selection, paste into exactly those tracks and
4681 only those tracks. This allows the user to be explicit and override
4682 the below "do the reasonable thing" logic. */
4683 ts = selection->tracks.filter_to_unique_playlists ();
4684 sort_track_selection (ts);
4686 /* Figure out which track to base the paste at. */
4687 TimeAxisView* base_track = NULL;
4688 if (_edit_point == Editing::EditAtMouse && entered_track) {
4689 /* With the mouse edit point, paste onto the track under the mouse. */
4690 base_track = entered_track;
4691 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4692 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4693 base_track = &entered_regionview->get_time_axis_view();
4694 } else if (_last_cut_copy_source_track) {
4695 /* Paste to the track that the cut/copy came from (see mantis #333). */
4696 base_track = _last_cut_copy_source_track;
4698 /* This is "impossible" since we've copied... well, do nothing. */
4702 /* Walk up to parent if necessary, so base track is a route. */
4703 while (base_track->get_parent()) {
4704 base_track = base_track->get_parent();
4707 /* Add base track and all tracks below it. The paste logic will select
4708 the appropriate object types from the cut buffer in relative order. */
4709 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4710 if ((*i)->order() >= base_track->order()) {
4715 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4716 sort_track_selection (ts);
4718 /* Add automation children of each track in order, for pasting several lines. */
4719 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4720 /* Add any automation children for pasting several lines */
4721 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4726 typedef RouteTimeAxisView::AutomationTracks ATracks;
4727 const ATracks& atracks = rtv->automation_tracks();
4728 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4729 i = ts.insert(i, a->second.get());
4734 /* We now have a list of trackviews starting at base_track, including
4735 automation children, in the order shown in the editor, e.g. R1,
4736 R1.A1, R1.A2, R2, R2.A1, ... */
4739 begin_reversible_command (Operations::paste);
4741 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4742 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4743 /* Only one line copied, and one automation track selected. Do a
4744 "greedy" paste from one automation type to another. */
4746 PasteContext ctx(paste_count, times, ItemCounts(), true);
4747 ts.front()->paste (position, *cut_buffer, ctx);
4751 /* Paste into tracks */
4753 PasteContext ctx(paste_count, times, ItemCounts(), false);
4754 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4755 (*i)->paste (position, *cut_buffer, ctx);
4759 commit_reversible_command ();
4763 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4765 if (regions.empty ()) {
4769 boost::shared_ptr<Playlist> playlist;
4770 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4771 RegionSelection foo;
4773 framepos_t const start_frame = regions.start ();
4774 framepos_t const end_frame = regions.end_frame ();
4775 framecnt_t const gap = end_frame - start_frame + 1;
4777 begin_reversible_command (Operations::duplicate_region);
4779 selection->clear_regions ();
4781 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4783 boost::shared_ptr<Region> r ((*i)->region());
4785 TimeAxisView& tv = (*i)->get_time_axis_view();
4786 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4787 latest_regionviews.clear ();
4788 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4790 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4791 playlist = (*i)->region()->playlist();
4792 playlist->clear_changes ();
4793 playlist->duplicate (r, position, gap, times);
4794 _session->add_command(new StatefulDiffCommand (playlist));
4798 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4802 selection->set (foo);
4805 commit_reversible_command ();
4809 Editor::duplicate_selection (float times)
4811 if (selection->time.empty() || selection->tracks.empty()) {
4815 boost::shared_ptr<Playlist> playlist;
4817 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4819 bool in_command = false;
4821 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4822 if ((playlist = (*i)->playlist()) == 0) {
4825 playlist->clear_changes ();
4827 if (clicked_selection) {
4828 playlist->duplicate_range (selection->time[clicked_selection], times);
4830 playlist->duplicate_ranges (selection->time, times);
4834 begin_reversible_command (_("duplicate range selection"));
4837 _session->add_command (new StatefulDiffCommand (playlist));
4842 // now "move" range selection to after the current range selection
4843 framecnt_t distance = 0;
4845 if (clicked_selection) {
4846 distance = selection->time[clicked_selection].end -
4847 selection->time[clicked_selection].start;
4849 distance = selection->time.end_frame() - selection->time.start();
4852 selection->move_time (distance);
4854 commit_reversible_command ();
4858 /** Reset all selected points to the relevant default value */
4860 Editor::reset_point_selection ()
4862 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4863 ARDOUR::AutomationList::iterator j = (*i)->model ();
4864 (*j)->value = (*i)->line().the_list()->default_value ();
4869 Editor::center_playhead ()
4871 float const page = _visible_canvas_width * samples_per_pixel;
4872 center_screen_internal (playhead_cursor->current_frame (), page);
4876 Editor::center_edit_point ()
4878 float const page = _visible_canvas_width * samples_per_pixel;
4879 center_screen_internal (get_preferred_edit_position(), page);
4882 /** Caller must begin and commit a reversible command */
4884 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4886 playlist->clear_changes ();
4888 _session->add_command (new StatefulDiffCommand (playlist));
4892 Editor::nudge_track (bool use_edit, bool forwards)
4894 boost::shared_ptr<Playlist> playlist;
4895 framepos_t distance;
4896 framepos_t next_distance;
4900 start = get_preferred_edit_position();
4905 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4909 if (selection->tracks.empty()) {
4913 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4914 bool in_command = false;
4916 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4918 if ((playlist = (*i)->playlist()) == 0) {
4922 playlist->clear_changes ();
4923 playlist->clear_owned_changes ();
4925 playlist->nudge_after (start, distance, forwards);
4928 begin_reversible_command (_("nudge track"));
4931 vector<Command*> cmds;
4933 playlist->rdiff (cmds);
4934 _session->add_commands (cmds);
4936 _session->add_command (new StatefulDiffCommand (playlist));
4940 commit_reversible_command ();
4945 Editor::remove_last_capture ()
4947 vector<string> choices;
4954 if (Config->get_verify_remove_last_capture()) {
4955 prompt = _("Do you really want to destroy the last capture?"
4956 "\n(This is destructive and cannot be undone)");
4958 choices.push_back (_("No, do nothing."));
4959 choices.push_back (_("Yes, destroy it."));
4961 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4963 if (prompter.run () == 1) {
4964 _session->remove_last_capture ();
4965 _regions->redisplay ();
4969 _session->remove_last_capture();
4970 _regions->redisplay ();
4975 Editor::normalize_region ()
4981 RegionSelection rs = get_regions_from_selection_and_entered ();
4987 NormalizeDialog dialog (rs.size() > 1);
4989 if (dialog.run () == RESPONSE_CANCEL) {
4993 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4996 /* XXX: should really only count audio regions here */
4997 int const regions = rs.size ();
4999 /* Make a list of the selected audio regions' maximum amplitudes, and also
5000 obtain the maximum amplitude of them all.
5002 list<double> max_amps;
5004 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5005 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5007 dialog.descend (1.0 / regions);
5008 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5011 /* the user cancelled the operation */
5015 max_amps.push_back (a);
5016 max_amp = max (max_amp, a);
5021 list<double>::const_iterator a = max_amps.begin ();
5022 bool in_command = false;
5024 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5025 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5030 arv->region()->clear_changes ();
5032 double const amp = dialog.normalize_individually() ? *a : max_amp;
5034 arv->audio_region()->normalize (amp, dialog.target ());
5037 begin_reversible_command (_("normalize"));
5040 _session->add_command (new StatefulDiffCommand (arv->region()));
5046 commit_reversible_command ();
5052 Editor::reset_region_scale_amplitude ()
5058 RegionSelection rs = get_regions_from_selection_and_entered ();
5064 bool in_command = false;
5066 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5067 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5070 arv->region()->clear_changes ();
5071 arv->audio_region()->set_scale_amplitude (1.0f);
5074 begin_reversible_command ("reset gain");
5077 _session->add_command (new StatefulDiffCommand (arv->region()));
5081 commit_reversible_command ();
5086 Editor::adjust_region_gain (bool up)
5088 RegionSelection rs = get_regions_from_selection_and_entered ();
5090 if (!_session || rs.empty()) {
5094 bool in_command = false;
5096 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5097 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5102 arv->region()->clear_changes ();
5104 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5112 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5115 begin_reversible_command ("adjust region gain");
5118 _session->add_command (new StatefulDiffCommand (arv->region()));
5122 commit_reversible_command ();
5128 Editor::reverse_region ()
5134 Reverse rev (*_session);
5135 apply_filter (rev, _("reverse regions"));
5139 Editor::strip_region_silence ()
5145 RegionSelection rs = get_regions_from_selection_and_entered ();
5151 std::list<RegionView*> audio_only;
5153 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5154 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5156 audio_only.push_back (arv);
5160 assert (!audio_only.empty());
5162 StripSilenceDialog d (_session, audio_only);
5163 int const r = d.run ();
5167 if (r == Gtk::RESPONSE_OK) {
5168 ARDOUR::AudioIntervalMap silences;
5169 d.silences (silences);
5170 StripSilence s (*_session, silences, d.fade_length());
5172 apply_filter (s, _("strip silence"), &d);
5177 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5179 Evoral::Sequence<Evoral::Beats>::Notes selected;
5180 mrv.selection_as_notelist (selected, true);
5182 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5183 v.push_back (selected);
5185 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5186 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5188 return op (mrv.midi_region()->model(), pos_beats, v);
5192 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5198 bool in_command = false;
5200 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5201 RegionSelection::const_iterator tmp = r;
5204 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5207 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5210 begin_reversible_command (op.name ());
5214 _session->add_command (cmd);
5222 commit_reversible_command ();
5227 Editor::fork_region ()
5229 RegionSelection rs = get_regions_from_selection_and_entered ();
5235 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5236 bool in_command = false;
5240 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5241 RegionSelection::iterator tmp = r;
5244 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5248 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5249 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5250 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5253 begin_reversible_command (_("Fork Region(s)"));
5256 playlist->clear_changes ();
5257 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5258 _session->add_command(new StatefulDiffCommand (playlist));
5260 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5268 commit_reversible_command ();
5273 Editor::quantize_region ()
5276 quantize_regions(get_regions_from_selection_and_entered ());
5281 Editor::quantize_regions (const RegionSelection& rs)
5283 if (rs.n_midi_regions() == 0) {
5287 if (!quantize_dialog) {
5288 quantize_dialog = new QuantizeDialog (*this);
5291 quantize_dialog->present ();
5292 const int r = quantize_dialog->run ();
5293 quantize_dialog->hide ();
5295 if (r == Gtk::RESPONSE_OK) {
5296 Quantize quant (quantize_dialog->snap_start(),
5297 quantize_dialog->snap_end(),
5298 quantize_dialog->start_grid_size(),
5299 quantize_dialog->end_grid_size(),
5300 quantize_dialog->strength(),
5301 quantize_dialog->swing(),
5302 quantize_dialog->threshold());
5304 apply_midi_note_edit_op (quant, rs);
5309 Editor::legatize_region (bool shrink_only)
5312 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5317 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5319 if (rs.n_midi_regions() == 0) {
5323 Legatize legatize(shrink_only);
5324 apply_midi_note_edit_op (legatize, rs);
5328 Editor::transform_region ()
5331 transform_regions(get_regions_from_selection_and_entered ());
5336 Editor::transform_regions (const RegionSelection& rs)
5338 if (rs.n_midi_regions() == 0) {
5345 const int r = td.run();
5348 if (r == Gtk::RESPONSE_OK) {
5349 Transform transform(td.get());
5350 apply_midi_note_edit_op(transform, rs);
5355 Editor::transpose_region ()
5358 transpose_regions(get_regions_from_selection_and_entered ());
5363 Editor::transpose_regions (const RegionSelection& rs)
5365 if (rs.n_midi_regions() == 0) {
5370 int const r = d.run ();
5372 if (r == RESPONSE_ACCEPT) {
5373 Transpose transpose(d.semitones ());
5374 apply_midi_note_edit_op (transpose, rs);
5379 Editor::insert_patch_change (bool from_context)
5381 RegionSelection rs = get_regions_from_selection_and_entered ();
5387 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5389 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5390 there may be more than one, but the PatchChangeDialog can only offer
5391 one set of patch menus.
5393 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5395 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5396 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5398 if (d.run() == RESPONSE_CANCEL) {
5402 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5403 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5405 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5406 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5413 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5415 RegionSelection rs = get_regions_from_selection_and_entered ();
5421 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5422 bool in_command = false;
5427 int const N = rs.size ();
5429 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5430 RegionSelection::iterator tmp = r;
5433 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5435 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5438 progress->descend (1.0 / N);
5441 if (arv->audio_region()->apply (filter, progress) == 0) {
5443 playlist->clear_changes ();
5444 playlist->clear_owned_changes ();
5447 begin_reversible_command (command);
5451 if (filter.results.empty ()) {
5453 /* no regions returned; remove the old one */
5454 playlist->remove_region (arv->region ());
5458 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5460 /* first region replaces the old one */
5461 playlist->replace_region (arv->region(), *res, (*res)->position());
5465 while (res != filter.results.end()) {
5466 playlist->add_region (*res, (*res)->position());
5472 /* We might have removed regions, which alters other regions' layering_index,
5473 so we need to do a recursive diff here.
5475 vector<Command*> cmds;
5476 playlist->rdiff (cmds);
5477 _session->add_commands (cmds);
5479 _session->add_command(new StatefulDiffCommand (playlist));
5483 progress->ascend ();
5492 commit_reversible_command ();
5497 Editor::external_edit_region ()
5503 Editor::reset_region_gain_envelopes ()
5505 RegionSelection rs = get_regions_from_selection_and_entered ();
5507 if (!_session || rs.empty()) {
5511 bool in_command = false;
5513 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5514 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5516 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5517 XMLNode& before (alist->get_state());
5519 arv->audio_region()->set_default_envelope ();
5522 begin_reversible_command (_("reset region gain"));
5525 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5530 commit_reversible_command ();
5535 Editor::set_region_gain_visibility (RegionView* rv)
5537 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5539 arv->update_envelope_visibility();
5544 Editor::set_gain_envelope_visibility ()
5550 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5551 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5553 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5559 Editor::toggle_gain_envelope_active ()
5561 if (_ignore_region_action) {
5565 RegionSelection rs = get_regions_from_selection_and_entered ();
5567 if (!_session || rs.empty()) {
5571 bool in_command = false;
5573 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5574 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5576 arv->region()->clear_changes ();
5577 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5580 begin_reversible_command (_("region gain envelope active"));
5583 _session->add_command (new StatefulDiffCommand (arv->region()));
5588 commit_reversible_command ();
5593 Editor::toggle_region_lock ()
5595 if (_ignore_region_action) {
5599 RegionSelection rs = get_regions_from_selection_and_entered ();
5601 if (!_session || rs.empty()) {
5605 begin_reversible_command (_("toggle region lock"));
5607 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5608 (*i)->region()->clear_changes ();
5609 (*i)->region()->set_locked (!(*i)->region()->locked());
5610 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5613 commit_reversible_command ();
5617 Editor::toggle_region_video_lock ()
5619 if (_ignore_region_action) {
5623 RegionSelection rs = get_regions_from_selection_and_entered ();
5625 if (!_session || rs.empty()) {
5629 begin_reversible_command (_("Toggle Video Lock"));
5631 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5632 (*i)->region()->clear_changes ();
5633 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5634 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5637 commit_reversible_command ();
5641 Editor::toggle_region_lock_style ()
5643 if (_ignore_region_action) {
5647 RegionSelection rs = get_regions_from_selection_and_entered ();
5649 if (!_session || rs.empty()) {
5653 begin_reversible_command (_("region lock style"));
5655 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5656 (*i)->region()->clear_changes ();
5657 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5658 (*i)->region()->set_position_lock_style (ns);
5659 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5662 commit_reversible_command ();
5666 Editor::toggle_opaque_region ()
5668 if (_ignore_region_action) {
5672 RegionSelection rs = get_regions_from_selection_and_entered ();
5674 if (!_session || rs.empty()) {
5678 begin_reversible_command (_("change region opacity"));
5680 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5681 (*i)->region()->clear_changes ();
5682 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5683 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5686 commit_reversible_command ();
5690 Editor::toggle_record_enable ()
5692 bool new_state = false;
5694 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5695 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5698 if (!rtav->is_track())
5702 new_state = !rtav->track()->rec_enable_control()->get_value();
5706 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5711 Editor::toggle_solo ()
5713 bool new_state = false;
5715 boost::shared_ptr<ControlList> cl (new ControlList);
5717 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5718 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5725 new_state = !rtav->route()->soloed ();
5729 cl->push_back (rtav->route()->solo_control());
5732 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5736 Editor::toggle_mute ()
5738 bool new_state = false;
5740 boost::shared_ptr<RouteList> rl (new RouteList);
5742 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5743 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5750 new_state = !rtav->route()->muted();
5754 rl->push_back (rtav->route());
5757 _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), new_state, Controllable::UseGroup);
5761 Editor::toggle_solo_isolate ()
5767 Editor::fade_range ()
5769 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5771 begin_reversible_command (_("fade range"));
5773 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5774 (*i)->fade_range (selection->time);
5777 commit_reversible_command ();
5782 Editor::set_fade_length (bool in)
5784 RegionSelection rs = get_regions_from_selection_and_entered ();
5790 /* we need a region to measure the offset from the start */
5792 RegionView* rv = rs.front ();
5794 framepos_t pos = get_preferred_edit_position();
5798 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5799 /* edit point is outside the relevant region */
5804 if (pos <= rv->region()->position()) {
5808 len = pos - rv->region()->position();
5809 cmd = _("set fade in length");
5811 if (pos >= rv->region()->last_frame()) {
5815 len = rv->region()->last_frame() - pos;
5816 cmd = _("set fade out length");
5819 bool in_command = false;
5821 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5822 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5828 boost::shared_ptr<AutomationList> alist;
5830 alist = tmp->audio_region()->fade_in();
5832 alist = tmp->audio_region()->fade_out();
5835 XMLNode &before = alist->get_state();
5838 tmp->audio_region()->set_fade_in_length (len);
5839 tmp->audio_region()->set_fade_in_active (true);
5841 tmp->audio_region()->set_fade_out_length (len);
5842 tmp->audio_region()->set_fade_out_active (true);
5846 begin_reversible_command (cmd);
5849 XMLNode &after = alist->get_state();
5850 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5854 commit_reversible_command ();
5859 Editor::set_fade_in_shape (FadeShape shape)
5861 RegionSelection rs = get_regions_from_selection_and_entered ();
5866 bool in_command = false;
5868 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5869 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5875 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5876 XMLNode &before = alist->get_state();
5878 tmp->audio_region()->set_fade_in_shape (shape);
5881 begin_reversible_command (_("set fade in shape"));
5884 XMLNode &after = alist->get_state();
5885 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5889 commit_reversible_command ();
5894 Editor::set_fade_out_shape (FadeShape shape)
5896 RegionSelection rs = get_regions_from_selection_and_entered ();
5901 bool in_command = false;
5903 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5904 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5910 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5911 XMLNode &before = alist->get_state();
5913 tmp->audio_region()->set_fade_out_shape (shape);
5916 begin_reversible_command (_("set fade out shape"));
5919 XMLNode &after = alist->get_state();
5920 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5924 commit_reversible_command ();
5929 Editor::set_fade_in_active (bool yn)
5931 RegionSelection rs = get_regions_from_selection_and_entered ();
5936 bool in_command = false;
5938 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5939 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5946 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5948 ar->clear_changes ();
5949 ar->set_fade_in_active (yn);
5952 begin_reversible_command (_("set fade in active"));
5955 _session->add_command (new StatefulDiffCommand (ar));
5959 commit_reversible_command ();
5964 Editor::set_fade_out_active (bool yn)
5966 RegionSelection rs = get_regions_from_selection_and_entered ();
5971 bool in_command = false;
5973 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5974 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5980 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5982 ar->clear_changes ();
5983 ar->set_fade_out_active (yn);
5986 begin_reversible_command (_("set fade out active"));
5989 _session->add_command(new StatefulDiffCommand (ar));
5993 commit_reversible_command ();
5998 Editor::toggle_region_fades (int dir)
6000 if (_ignore_region_action) {
6004 boost::shared_ptr<AudioRegion> ar;
6007 RegionSelection rs = get_regions_from_selection_and_entered ();
6013 RegionSelection::iterator i;
6014 for (i = rs.begin(); i != rs.end(); ++i) {
6015 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6017 yn = ar->fade_out_active ();
6019 yn = ar->fade_in_active ();
6025 if (i == rs.end()) {
6029 /* XXX should this undo-able? */
6030 bool in_command = false;
6032 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6033 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6036 ar->clear_changes ();
6038 if (dir == 1 || dir == 0) {
6039 ar->set_fade_in_active (!yn);
6042 if (dir == -1 || dir == 0) {
6043 ar->set_fade_out_active (!yn);
6046 begin_reversible_command (_("toggle fade active"));
6049 _session->add_command(new StatefulDiffCommand (ar));
6053 commit_reversible_command ();
6058 /** Update region fade visibility after its configuration has been changed */
6060 Editor::update_region_fade_visibility ()
6062 bool _fade_visibility = _session->config.get_show_region_fades ();
6064 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6065 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6067 if (_fade_visibility) {
6068 v->audio_view()->show_all_fades ();
6070 v->audio_view()->hide_all_fades ();
6077 Editor::set_edit_point ()
6082 if (!mouse_frame (where, ignored)) {
6088 if (selection->markers.empty()) {
6090 mouse_add_new_marker (where);
6095 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6098 loc->move_to (where);
6104 Editor::set_playhead_cursor ()
6106 if (entered_marker) {
6107 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6112 if (!mouse_frame (where, ignored)) {
6119 _session->request_locate (where, _session->transport_rolling());
6123 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6124 cancel_time_selection();
6129 Editor::split_region ()
6131 if (_drags->active ()) {
6135 //if a range is selected, separate it
6136 if ( !selection->time.empty()) {
6137 separate_regions_between (selection->time);
6141 //if no range was selected, try to find some regions to split
6142 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6144 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6146 framepos_t where = get_preferred_edit_position ();
6152 split_regions_at (where, rs);
6157 Editor::select_next_route()
6159 if (selection->tracks.empty()) {
6160 selection->set (track_views.front());
6164 TimeAxisView* current = selection->tracks.front();
6168 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6169 if (*i == current) {
6171 if (i != track_views.end()) {
6174 current = (*(track_views.begin()));
6175 //selection->set (*(track_views.begin()));
6180 rui = dynamic_cast<RouteUI *>(current);
6181 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6183 selection->set(current);
6185 ensure_time_axis_view_is_visible (*current, false);
6189 Editor::select_prev_route()
6191 if (selection->tracks.empty()) {
6192 selection->set (track_views.front());
6196 TimeAxisView* current = selection->tracks.front();
6200 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6201 if (*i == current) {
6203 if (i != track_views.rend()) {
6206 current = *(track_views.rbegin());
6211 rui = dynamic_cast<RouteUI *>(current);
6212 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6214 selection->set (current);
6216 ensure_time_axis_view_is_visible (*current, false);
6220 Editor::set_loop_from_selection (bool play)
6222 if (_session == 0) {
6226 framepos_t start, end;
6227 if (!get_selection_extents ( start, end))
6230 set_loop_range (start, end, _("set loop range from selection"));
6233 _session->request_play_loop (true, true);
6238 Editor::set_loop_from_region (bool play)
6240 framepos_t start, end;
6241 if (!get_selection_extents ( start, end))
6244 set_loop_range (start, end, _("set loop range from region"));
6247 _session->request_locate (start, true);
6248 _session->request_play_loop (true);
6253 Editor::set_punch_from_selection ()
6255 if (_session == 0) {
6259 framepos_t start, end;
6260 if (!get_selection_extents ( start, end))
6263 set_punch_range (start, end, _("set punch range from selection"));
6267 Editor::set_session_extents_from_selection ()
6269 if (_session == 0) {
6273 framepos_t start, end;
6274 if (!get_selection_extents ( start, end))
6278 if ((loc = _session->locations()->session_range_location()) == 0) {
6279 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6281 XMLNode &before = loc->get_state();
6283 _session->set_session_extents ( start, end );
6285 XMLNode &after = loc->get_state();
6287 begin_reversible_command (_("set session start/end from selection"));
6289 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6291 commit_reversible_command ();
6296 Editor::set_punch_start_from_edit_point ()
6300 framepos_t start = 0;
6301 framepos_t end = max_framepos;
6303 //use the existing punch end, if any
6304 Location* tpl = transport_punch_location();
6309 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6310 start = _session->audible_frame();
6312 start = get_preferred_edit_position();
6315 //snap the selection start/end
6318 //if there's not already a sensible selection endpoint, go "forever"
6319 if ( start > end ) {
6323 set_punch_range (start, end, _("set punch start from EP"));
6329 Editor::set_punch_end_from_edit_point ()
6333 framepos_t start = 0;
6334 framepos_t end = max_framepos;
6336 //use the existing punch start, if any
6337 Location* tpl = transport_punch_location();
6339 start = tpl->start();
6342 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6343 end = _session->audible_frame();
6345 end = get_preferred_edit_position();
6348 //snap the selection start/end
6351 set_punch_range (start, end, _("set punch end from EP"));
6357 Editor::set_loop_start_from_edit_point ()
6361 framepos_t start = 0;
6362 framepos_t end = max_framepos;
6364 //use the existing loop end, if any
6365 Location* tpl = transport_loop_location();
6370 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6371 start = _session->audible_frame();
6373 start = get_preferred_edit_position();
6376 //snap the selection start/end
6379 //if there's not already a sensible selection endpoint, go "forever"
6380 if ( start > end ) {
6384 set_loop_range (start, end, _("set loop start from EP"));
6390 Editor::set_loop_end_from_edit_point ()
6394 framepos_t start = 0;
6395 framepos_t end = max_framepos;
6397 //use the existing loop start, if any
6398 Location* tpl = transport_loop_location();
6400 start = tpl->start();
6403 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6404 end = _session->audible_frame();
6406 end = get_preferred_edit_position();
6409 //snap the selection start/end
6412 set_loop_range (start, end, _("set loop end from EP"));
6417 Editor::set_punch_from_region ()
6419 framepos_t start, end;
6420 if (!get_selection_extents ( start, end))
6423 set_punch_range (start, end, _("set punch range from region"));
6427 Editor::pitch_shift_region ()
6429 RegionSelection rs = get_regions_from_selection_and_entered ();
6431 RegionSelection audio_rs;
6432 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6433 if (dynamic_cast<AudioRegionView*> (*i)) {
6434 audio_rs.push_back (*i);
6438 if (audio_rs.empty()) {
6442 pitch_shift (audio_rs, 1.2);
6446 Editor::set_tempo_from_region ()
6448 RegionSelection rs = get_regions_from_selection_and_entered ();
6450 if (!_session || rs.empty()) {
6454 RegionView* rv = rs.front();
6456 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6460 Editor::use_range_as_bar ()
6462 framepos_t start, end;
6463 if (get_edit_op_range (start, end)) {
6464 define_one_bar (start, end);
6469 Editor::define_one_bar (framepos_t start, framepos_t end)
6471 framepos_t length = end - start;
6473 const Meter& m (_session->tempo_map().meter_at_frame (start));
6475 /* length = 1 bar */
6477 /* We're going to deliver a constant tempo here,
6478 so we can use frames per beat to determine length.
6479 now we want frames per beat.
6480 we have frames per bar, and beats per bar, so ...
6483 /* XXXX METER MATH */
6485 double frames_per_beat = length / m.divisions_per_bar();
6487 /* beats per minute = */
6489 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6491 /* now decide whether to:
6493 (a) set global tempo
6494 (b) add a new tempo marker
6498 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6500 bool do_global = false;
6502 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6504 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6505 at the start, or create a new marker
6508 vector<string> options;
6509 options.push_back (_("Cancel"));
6510 options.push_back (_("Add new marker"));
6511 options.push_back (_("Set global tempo"));
6514 _("Define one bar"),
6515 _("Do you want to set the global tempo or add a new tempo marker?"),
6519 c.set_default_response (2);
6535 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6536 if the marker is at the region starter, change it, otherwise add
6541 begin_reversible_command (_("set tempo from region"));
6542 XMLNode& before (_session->tempo_map().get_state());
6545 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6546 } else if (t.frame() == start) {
6547 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6549 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), 0.0, start, TempoSection::Constant, AudioTime);
6552 XMLNode& after (_session->tempo_map().get_state());
6554 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6555 commit_reversible_command ();
6559 Editor::split_region_at_transients ()
6561 AnalysisFeatureList positions;
6563 RegionSelection rs = get_regions_from_selection_and_entered ();
6565 if (!_session || rs.empty()) {
6569 begin_reversible_command (_("split regions"));
6571 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6573 RegionSelection::iterator tmp;
6578 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6581 ar->transients (positions);
6582 split_region_at_points ((*i)->region(), positions, true);
6589 commit_reversible_command ();
6594 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6596 bool use_rhythmic_rodent = false;
6598 boost::shared_ptr<Playlist> pl = r->playlist();
6600 list<boost::shared_ptr<Region> > new_regions;
6606 if (positions.empty()) {
6610 if (positions.size() > 20 && can_ferret) {
6611 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);
6612 MessageDialog msg (msgstr,
6615 Gtk::BUTTONS_OK_CANCEL);
6618 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6619 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6621 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6624 msg.set_title (_("Excessive split?"));
6627 int response = msg.run();
6633 case RESPONSE_APPLY:
6634 use_rhythmic_rodent = true;
6641 if (use_rhythmic_rodent) {
6642 show_rhythm_ferret ();
6646 AnalysisFeatureList::const_iterator x;
6648 pl->clear_changes ();
6649 pl->clear_owned_changes ();
6651 x = positions.begin();
6653 if (x == positions.end()) {
6658 pl->remove_region (r);
6662 framepos_t rstart = r->first_frame ();
6663 framepos_t rend = r->last_frame ();
6665 while (x != positions.end()) {
6667 /* deal with positons that are out of scope of present region bounds */
6668 if (*x <= rstart || *x > rend) {
6673 /* file start = original start + how far we from the initial position ? */
6675 framepos_t file_start = r->start() + pos;
6677 /* length = next position - current position */
6679 framepos_t len = (*x) - pos - rstart;
6681 /* XXX we do we really want to allow even single-sample regions?
6682 * shouldn't we have some kind of lower limit on region size?
6691 if (RegionFactory::region_name (new_name, r->name())) {
6695 /* do NOT announce new regions 1 by one, just wait till they are all done */
6699 plist.add (ARDOUR::Properties::start, file_start);
6700 plist.add (ARDOUR::Properties::length, len);
6701 plist.add (ARDOUR::Properties::name, new_name);
6702 plist.add (ARDOUR::Properties::layer, 0);
6703 // TODO set transients_offset
6705 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6706 /* because we set annouce to false, manually add the new region to the
6709 RegionFactory::map_add (nr);
6711 pl->add_region (nr, rstart + pos);
6714 new_regions.push_front(nr);
6723 RegionFactory::region_name (new_name, r->name());
6725 /* Add the final region */
6728 plist.add (ARDOUR::Properties::start, r->start() + pos);
6729 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6730 plist.add (ARDOUR::Properties::name, new_name);
6731 plist.add (ARDOUR::Properties::layer, 0);
6733 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6734 /* because we set annouce to false, manually add the new region to the
6737 RegionFactory::map_add (nr);
6738 pl->add_region (nr, r->position() + pos);
6741 new_regions.push_front(nr);
6746 /* We might have removed regions, which alters other regions' layering_index,
6747 so we need to do a recursive diff here.
6749 vector<Command*> cmds;
6751 _session->add_commands (cmds);
6753 _session->add_command (new StatefulDiffCommand (pl));
6757 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6758 set_selected_regionview_from_region_list ((*i), Selection::Add);
6764 Editor::place_transient()
6770 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6776 framepos_t where = get_preferred_edit_position();
6778 begin_reversible_command (_("place transient"));
6780 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6781 (*r)->region()->add_transient(where);
6784 commit_reversible_command ();
6788 Editor::remove_transient(ArdourCanvas::Item* item)
6794 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6797 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6798 _arv->remove_transient (*(float*) _line->get_data ("position"));
6802 Editor::snap_regions_to_grid ()
6804 list <boost::shared_ptr<Playlist > > used_playlists;
6806 RegionSelection rs = get_regions_from_selection_and_entered ();
6808 if (!_session || rs.empty()) {
6812 begin_reversible_command (_("snap regions to grid"));
6814 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6816 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6818 if (!pl->frozen()) {
6819 /* we haven't seen this playlist before */
6821 /* remember used playlists so we can thaw them later */
6822 used_playlists.push_back(pl);
6826 framepos_t start_frame = (*r)->region()->first_frame ();
6827 snap_to (start_frame);
6828 (*r)->region()->set_position (start_frame);
6831 while (used_playlists.size() > 0) {
6832 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6834 used_playlists.pop_front();
6837 commit_reversible_command ();
6841 Editor::close_region_gaps ()
6843 list <boost::shared_ptr<Playlist > > used_playlists;
6845 RegionSelection rs = get_regions_from_selection_and_entered ();
6847 if (!_session || rs.empty()) {
6851 Dialog dialog (_("Close Region Gaps"));
6854 table.set_spacings (12);
6855 table.set_border_width (12);
6856 Label* l = manage (left_aligned_label (_("Crossfade length")));
6857 table.attach (*l, 0, 1, 0, 1);
6859 SpinButton spin_crossfade (1, 0);
6860 spin_crossfade.set_range (0, 15);
6861 spin_crossfade.set_increments (1, 1);
6862 spin_crossfade.set_value (5);
6863 table.attach (spin_crossfade, 1, 2, 0, 1);
6865 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6867 l = manage (left_aligned_label (_("Pull-back length")));
6868 table.attach (*l, 0, 1, 1, 2);
6870 SpinButton spin_pullback (1, 0);
6871 spin_pullback.set_range (0, 100);
6872 spin_pullback.set_increments (1, 1);
6873 spin_pullback.set_value(30);
6874 table.attach (spin_pullback, 1, 2, 1, 2);
6876 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6878 dialog.get_vbox()->pack_start (table);
6879 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6880 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6883 if (dialog.run () == RESPONSE_CANCEL) {
6887 framepos_t crossfade_len = spin_crossfade.get_value();
6888 framepos_t pull_back_frames = spin_pullback.get_value();
6890 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6891 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6893 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6895 begin_reversible_command (_("close region gaps"));
6898 boost::shared_ptr<Region> last_region;
6900 rs.sort_by_position_and_track();
6902 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6904 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6906 if (!pl->frozen()) {
6907 /* we haven't seen this playlist before */
6909 /* remember used playlists so we can thaw them later */
6910 used_playlists.push_back(pl);
6914 framepos_t position = (*r)->region()->position();
6916 if (idx == 0 || position < last_region->position()){
6917 last_region = (*r)->region();
6922 (*r)->region()->trim_front( (position - pull_back_frames));
6923 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6925 last_region = (*r)->region();
6930 while (used_playlists.size() > 0) {
6931 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6933 used_playlists.pop_front();
6936 commit_reversible_command ();
6940 Editor::tab_to_transient (bool forward)
6942 AnalysisFeatureList positions;
6944 RegionSelection rs = get_regions_from_selection_and_entered ();
6950 framepos_t pos = _session->audible_frame ();
6952 if (!selection->tracks.empty()) {
6954 /* don't waste time searching for transients in duplicate playlists.
6957 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6959 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6961 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6964 boost::shared_ptr<Track> tr = rtv->track();
6966 boost::shared_ptr<Playlist> pl = tr->playlist ();
6968 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6971 positions.push_back (result);
6984 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6985 (*r)->region()->get_transients (positions);
6989 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6992 AnalysisFeatureList::iterator x;
6994 for (x = positions.begin(); x != positions.end(); ++x) {
7000 if (x != positions.end ()) {
7001 _session->request_locate (*x);
7005 AnalysisFeatureList::reverse_iterator x;
7007 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7013 if (x != positions.rend ()) {
7014 _session->request_locate (*x);
7020 Editor::playhead_forward_to_grid ()
7026 framepos_t pos = playhead_cursor->current_frame ();
7027 if (pos < max_framepos - 1) {
7029 snap_to_internal (pos, RoundUpAlways, false);
7030 _session->request_locate (pos);
7036 Editor::playhead_backward_to_grid ()
7042 framepos_t pos = playhead_cursor->current_frame ();
7045 snap_to_internal (pos, RoundDownAlways, false);
7046 _session->request_locate (pos);
7051 Editor::set_track_height (Height h)
7053 TrackSelection& ts (selection->tracks);
7055 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7056 (*x)->set_height_enum (h);
7061 Editor::toggle_tracks_active ()
7063 TrackSelection& ts (selection->tracks);
7065 bool target = false;
7071 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7072 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7076 target = !rtv->_route->active();
7079 rtv->_route->set_active (target, this);
7085 Editor::remove_tracks ()
7087 /* this will delete GUI objects that may be the subject of an event
7088 handler in which this method is called. Defer actual deletion to the
7089 next idle callback, when all event handling is finished.
7091 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7095 Editor::idle_remove_tracks ()
7097 Session::StateProtector sp (_session);
7099 return false; /* do not call again */
7103 Editor::_remove_tracks ()
7105 TrackSelection& ts (selection->tracks);
7111 vector<string> choices;
7115 const char* trackstr;
7117 vector<boost::shared_ptr<Route> > routes;
7118 bool special_bus = false;
7120 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7121 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7125 if (rtv->is_track()) {
7130 routes.push_back (rtv->_route);
7132 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7137 if (special_bus && !Config->get_allow_special_bus_removal()) {
7138 MessageDialog msg (_("That would be bad news ...."),
7142 msg.set_secondary_text (string_compose (_(
7143 "Removing the master or monitor bus is such a bad idea\n\
7144 that %1 is not going to allow it.\n\
7146 If you really want to do this sort of thing\n\
7147 edit your ardour.rc file to set the\n\
7148 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7155 if (ntracks + nbusses == 0) {
7159 trackstr = P_("track", "tracks", ntracks);
7160 busstr = P_("bus", "busses", nbusses);
7164 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7165 "(You may also lose the playlists associated with the %2)\n\n"
7166 "This action cannot be undone, and the session file will be overwritten!"),
7167 ntracks, trackstr, nbusses, busstr);
7169 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7170 "(You may also lose the playlists associated with the %2)\n\n"
7171 "This action cannot be undone, and the session file will be overwritten!"),
7174 } else if (nbusses) {
7175 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7176 "This action cannot be undone, and the session file will be overwritten"),
7180 choices.push_back (_("No, do nothing."));
7181 if (ntracks + nbusses > 1) {
7182 choices.push_back (_("Yes, remove them."));
7184 choices.push_back (_("Yes, remove it."));
7189 title = string_compose (_("Remove %1"), trackstr);
7191 title = string_compose (_("Remove %1"), busstr);
7194 Choice prompter (title, prompt, choices);
7196 if (prompter.run () != 1) {
7201 DisplaySuspender ds;
7202 boost::shared_ptr<RouteList> rl (new RouteList);
7203 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7206 _session->remove_routes (rl);
7208 /* TrackSelection and RouteList leave scope,
7209 * destructors are called,
7210 * diskstream drops references, save_state is called (again for every track)
7215 Editor::do_insert_time ()
7217 if (selection->tracks.empty()) {
7221 InsertRemoveTimeDialog d (*this);
7222 int response = d.run ();
7224 if (response != RESPONSE_OK) {
7228 if (d.distance() == 0) {
7233 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7235 d.intersected_region_action (),
7239 d.move_glued_markers(),
7240 d.move_locked_markers(),
7246 Editor::insert_time (
7247 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7248 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7252 if (Config->get_edit_mode() == Lock) {
7255 bool in_command = false;
7257 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7259 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7263 /* don't operate on any playlist more than once, which could
7264 * happen if "all playlists" is enabled, but there is more
7265 * than 1 track using playlists "from" a given track.
7268 set<boost::shared_ptr<Playlist> > pl;
7270 if (all_playlists) {
7271 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7272 if (rtav && rtav->track ()) {
7273 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7274 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7279 if ((*x)->playlist ()) {
7280 pl.insert ((*x)->playlist ());
7284 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7286 (*i)->clear_changes ();
7287 (*i)->clear_owned_changes ();
7289 if (opt == SplitIntersected) {
7293 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7296 begin_reversible_command (_("insert time"));
7299 vector<Command*> cmds;
7301 _session->add_commands (cmds);
7303 _session->add_command (new StatefulDiffCommand (*i));
7307 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7310 begin_reversible_command (_("insert time"));
7313 rtav->route ()->shift (pos, frames);
7320 XMLNode& before (_session->locations()->get_state());
7321 Locations::LocationList copy (_session->locations()->list());
7323 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7325 Locations::LocationList::const_iterator tmp;
7327 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7328 bool const was_locked = (*i)->locked ();
7329 if (locked_markers_too) {
7333 if ((*i)->start() >= pos) {
7334 // move end first, in case we're moving by more than the length of the range
7335 if (!(*i)->is_mark()) {
7336 (*i)->set_end ((*i)->end() + frames);
7338 (*i)->set_start ((*i)->start() + frames);
7350 begin_reversible_command (_("insert time"));
7353 XMLNode& after (_session->locations()->get_state());
7354 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7360 begin_reversible_command (_("insert time"));
7363 XMLNode& before (_session->tempo_map().get_state());
7364 _session->tempo_map().insert_time (pos, frames);
7365 XMLNode& after (_session->tempo_map().get_state());
7366 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7370 commit_reversible_command ();
7375 Editor::do_remove_time ()
7377 if (selection->tracks.empty()) {
7381 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7382 InsertRemoveTimeDialog d (*this, true);
7384 int response = d.run ();
7386 if (response != RESPONSE_OK) {
7390 framecnt_t distance = d.distance();
7392 if (distance == 0) {
7402 d.move_glued_markers(),
7403 d.move_locked_markers(),
7409 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7410 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7412 if (Config->get_edit_mode() == Lock) {
7413 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7416 bool in_command = false;
7418 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7420 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7424 XMLNode &before = pl->get_state();
7426 std::list<AudioRange> rl;
7427 AudioRange ar(pos, pos+frames, 0);
7430 pl->shift (pos, -frames, true, ignore_music_glue);
7433 begin_reversible_command (_("remove time"));
7436 XMLNode &after = pl->get_state();
7438 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7442 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7445 begin_reversible_command (_("remove time"));
7448 rtav->route ()->shift (pos, -frames);
7452 std::list<Location*> loc_kill_list;
7457 XMLNode& before (_session->locations()->get_state());
7458 Locations::LocationList copy (_session->locations()->list());
7460 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7461 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7463 bool const was_locked = (*i)->locked ();
7464 if (locked_markers_too) {
7468 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7469 if ((*i)->end() >= pos
7470 && (*i)->end() < pos+frames
7471 && (*i)->start() >= pos
7472 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7474 loc_kill_list.push_back(*i);
7475 } else { // only start or end is included, try to do the right thing
7476 // move start before moving end, to avoid trying to move the end to before the start
7477 // if we're removing more time than the length of the range
7478 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7479 // start is within cut
7480 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7482 } else if ((*i)->start() >= pos+frames) {
7483 // start (and thus entire range) lies beyond end of cut
7484 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7487 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7488 // end is inside cut
7489 (*i)->set_end (pos); // bring the end to the cut
7491 } else if ((*i)->end() >= pos+frames) {
7492 // end is beyond end of cut
7493 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7498 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7499 loc_kill_list.push_back(*i);
7501 } else if ((*i)->start() >= pos) {
7502 (*i)->set_start ((*i)->start() -frames);
7512 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7513 _session->locations()->remove( *i );
7518 begin_reversible_command (_("remove time"));
7521 XMLNode& after (_session->locations()->get_state());
7522 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7527 XMLNode& before (_session->tempo_map().get_state());
7529 if (_session->tempo_map().remove_time (pos, frames) ) {
7531 begin_reversible_command (_("remove time"));
7534 XMLNode& after (_session->tempo_map().get_state());
7535 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7540 commit_reversible_command ();
7545 Editor::fit_selection ()
7547 if (!selection->tracks.empty()) {
7548 fit_tracks (selection->tracks);
7552 /* no selected tracks - use tracks with selected regions */
7554 if (!selection->regions.empty()) {
7555 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7556 tvl.push_back (&(*r)->get_time_axis_view ());
7562 } else if (internal_editing()) {
7563 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7566 if (entered_track) {
7567 tvl.push_back (entered_track);
7576 Editor::fit_tracks (TrackViewList & tracks)
7578 if (tracks.empty()) {
7582 uint32_t child_heights = 0;
7583 int visible_tracks = 0;
7585 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7587 if (!(*t)->marked_for_display()) {
7591 child_heights += (*t)->effective_height() - (*t)->current_height();
7595 /* compute the per-track height from:
7597 total canvas visible height -
7598 height that will be taken by visible children of selected
7599 tracks - height of the ruler/hscroll area
7601 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7602 double first_y_pos = DBL_MAX;
7604 if (h < TimeAxisView::preset_height (HeightSmall)) {
7605 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7606 /* too small to be displayed */
7610 undo_visual_stack.push_back (current_visual_state (true));
7611 PBD::Unwinder<bool> nsv (no_save_visual, true);
7613 /* build a list of all tracks, including children */
7616 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7618 TimeAxisView::Children c = (*i)->get_child_list ();
7619 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7620 all.push_back (j->get());
7625 // find selection range.
7626 // if someone knows how to user TrackViewList::iterator for this
7628 int selected_top = -1;
7629 int selected_bottom = -1;
7631 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7632 if ((*t)->marked_for_display ()) {
7633 if (tracks.contains(*t)) {
7634 if (selected_top == -1) {
7637 selected_bottom = i;
7643 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7644 if ((*t)->marked_for_display ()) {
7645 if (tracks.contains(*t)) {
7646 (*t)->set_height (h);
7647 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7649 if (i > selected_top && i < selected_bottom) {
7650 hide_track_in_display (*t);
7657 set the controls_layout height now, because waiting for its size
7658 request signal handler will cause the vertical adjustment setting to fail
7661 controls_layout.property_height () = _full_canvas_height;
7662 vertical_adjustment.set_value (first_y_pos);
7664 redo_visual_stack.push_back (current_visual_state (true));
7666 visible_tracks_selector.set_text (_("Sel"));
7670 Editor::save_visual_state (uint32_t n)
7672 while (visual_states.size() <= n) {
7673 visual_states.push_back (0);
7676 if (visual_states[n] != 0) {
7677 delete visual_states[n];
7680 visual_states[n] = current_visual_state (true);
7685 Editor::goto_visual_state (uint32_t n)
7687 if (visual_states.size() <= n) {
7691 if (visual_states[n] == 0) {
7695 use_visual_state (*visual_states[n]);
7699 Editor::start_visual_state_op (uint32_t n)
7701 save_visual_state (n);
7703 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7705 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7706 pup->set_text (buf);
7711 Editor::cancel_visual_state_op (uint32_t n)
7713 goto_visual_state (n);
7717 Editor::toggle_region_mute ()
7719 if (_ignore_region_action) {
7723 RegionSelection rs = get_regions_from_selection_and_entered ();
7729 if (rs.size() > 1) {
7730 begin_reversible_command (_("mute regions"));
7732 begin_reversible_command (_("mute region"));
7735 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7737 (*i)->region()->playlist()->clear_changes ();
7738 (*i)->region()->set_muted (!(*i)->region()->muted ());
7739 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7743 commit_reversible_command ();
7747 Editor::combine_regions ()
7749 /* foreach track with selected regions, take all selected regions
7750 and join them into a new region containing the subregions (as a
7754 typedef set<RouteTimeAxisView*> RTVS;
7757 if (selection->regions.empty()) {
7761 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7762 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7765 tracks.insert (rtv);
7769 begin_reversible_command (_("combine regions"));
7771 vector<RegionView*> new_selection;
7773 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7776 if ((rv = (*i)->combine_regions ()) != 0) {
7777 new_selection.push_back (rv);
7781 selection->clear_regions ();
7782 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7783 selection->add (*i);
7786 commit_reversible_command ();
7790 Editor::uncombine_regions ()
7792 typedef set<RouteTimeAxisView*> RTVS;
7795 if (selection->regions.empty()) {
7799 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7800 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7803 tracks.insert (rtv);
7807 begin_reversible_command (_("uncombine regions"));
7809 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7810 (*i)->uncombine_regions ();
7813 commit_reversible_command ();
7817 Editor::toggle_midi_input_active (bool flip_others)
7820 boost::shared_ptr<RouteList> rl (new RouteList);
7822 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7823 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7829 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7832 rl->push_back (rtav->route());
7833 onoff = !mt->input_active();
7837 _session->set_exclusive_input_active (rl, onoff, flip_others);
7844 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7846 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7847 lock_dialog->get_vbox()->pack_start (*padlock);
7849 ArdourButton* b = manage (new ArdourButton);
7850 b->set_name ("lock button");
7851 b->set_text (_("Click to unlock"));
7852 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7853 lock_dialog->get_vbox()->pack_start (*b);
7855 lock_dialog->get_vbox()->show_all ();
7856 lock_dialog->set_size_request (200, 200);
7859 delete _main_menu_disabler;
7860 _main_menu_disabler = new MainMenuDisabler;
7862 lock_dialog->present ();
7868 lock_dialog->hide ();
7870 delete _main_menu_disabler;
7871 _main_menu_disabler = 0;
7873 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7874 start_lock_event_timing ();
7879 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7881 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7885 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7887 Timers::TimerSuspender t;
7888 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7889 Gtkmm2ext::UI::instance()->flush_pending ();
7893 Editor::bring_all_sources_into_session ()
7900 ArdourDialog w (_("Moving embedded files into session folder"));
7901 w.get_vbox()->pack_start (msg);
7904 /* flush all pending GUI events because we're about to start copying
7908 Timers::TimerSuspender t;
7909 Gtkmm2ext::UI::instance()->flush_pending ();
7913 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));