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 current_interthread_info = 0;
3925 Editor::bounce_range_selection (bool replace, bool enable_processing)
3927 if (selection->time.empty()) {
3931 TrackSelection views = selection->tracks;
3933 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3935 if (enable_processing) {
3937 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3939 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3941 _("You can't perform this operation because the processing of the signal "
3942 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3943 "You can do this without processing, which is a different operation.")
3945 d.set_title (_("Cannot bounce"));
3952 framepos_t start = selection->time[clicked_selection].start;
3953 framepos_t end = selection->time[clicked_selection].end;
3954 framepos_t cnt = end - start + 1;
3955 bool in_command = false;
3957 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3959 RouteTimeAxisView* rtv;
3961 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3965 boost::shared_ptr<Playlist> playlist;
3967 if ((playlist = rtv->playlist()) == 0) {
3971 InterThreadInfo itt;
3973 playlist->clear_changes ();
3974 playlist->clear_owned_changes ();
3976 boost::shared_ptr<Region> r;
3978 if (enable_processing) {
3979 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3981 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3989 list<AudioRange> ranges;
3990 ranges.push_back (AudioRange (start, start+cnt, 0));
3991 playlist->cut (ranges); // discard result
3992 playlist->add_region (r, start);
3996 begin_reversible_command (_("bounce range"));
3999 vector<Command*> cmds;
4000 playlist->rdiff (cmds);
4001 _session->add_commands (cmds);
4003 _session->add_command (new StatefulDiffCommand (playlist));
4007 commit_reversible_command ();
4011 /** Delete selected regions, automation points or a time range */
4015 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4016 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4017 bool deleted = false;
4018 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4019 deleted = current_mixer_strip->delete_processors ();
4025 /** Cut selected regions, automation points or a time range */
4032 /** Copy selected regions, automation points or a time range */
4040 /** @return true if a Cut, Copy or Clear is possible */
4042 Editor::can_cut_copy () const
4044 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4051 /** Cut, copy or clear selected regions, automation points or a time range.
4052 * @param op Operation (Delete, Cut, Copy or Clear)
4055 Editor::cut_copy (CutCopyOp op)
4057 /* only cancel selection if cut/copy is successful.*/
4063 opname = _("delete");
4072 opname = _("clear");
4076 /* if we're deleting something, and the mouse is still pressed,
4077 the thing we started a drag for will be gone when we release
4078 the mouse button(s). avoid this. see part 2 at the end of
4082 if (op == Delete || op == Cut || op == Clear) {
4083 if (_drags->active ()) {
4088 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4089 cut_buffer->clear ();
4091 if (entered_marker) {
4093 /* cut/delete op while pointing at a marker */
4096 Location* loc = find_location_from_marker (entered_marker, ignored);
4098 if (_session && loc) {
4099 entered_marker = NULL;
4100 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4107 switch (mouse_mode) {
4110 begin_reversible_command (opname + ' ' + X_("MIDI"));
4112 commit_reversible_command ();
4118 bool did_edit = false;
4120 if (!selection->regions.empty() || !selection->points.empty()) {
4121 begin_reversible_command (opname + ' ' + _("objects"));
4124 if (!selection->regions.empty()) {
4125 cut_copy_regions (op, selection->regions);
4127 if (op == Cut || op == Delete) {
4128 selection->clear_regions ();
4132 if (!selection->points.empty()) {
4133 cut_copy_points (op);
4135 if (op == Cut || op == Delete) {
4136 selection->clear_points ();
4139 } else if (selection->time.empty()) {
4140 framepos_t start, end;
4141 /* no time selection, see if we can get an edit range
4144 if (get_edit_op_range (start, end)) {
4145 selection->set (start, end);
4147 } else if (!selection->time.empty()) {
4148 begin_reversible_command (opname + ' ' + _("range"));
4151 cut_copy_ranges (op);
4153 if (op == Cut || op == Delete) {
4154 selection->clear_time ();
4159 /* reset repeated paste state */
4162 commit_reversible_command ();
4165 if (op == Delete || op == Cut || op == Clear) {
4170 struct AutomationRecord {
4171 AutomationRecord () : state (0) , line(NULL) {}
4172 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4174 XMLNode* state; ///< state before any operation
4175 const AutomationLine* line; ///< line this came from
4176 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4179 /** Cut, copy or clear selected automation points.
4180 * @param op Operation (Cut, Copy or Clear)
4183 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4185 if (selection->points.empty ()) {
4189 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4190 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4192 /* Keep a record of the AutomationLists that we end up using in this operation */
4193 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4196 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4197 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4198 const AutomationLine& line = (*i)->line();
4199 const boost::shared_ptr<AutomationList> al = line.the_list();
4200 if (lists.find (al) == lists.end ()) {
4201 /* We haven't seen this list yet, so make a record for it. This includes
4202 taking a copy of its current state, in case this is needed for undo later.
4204 lists[al] = AutomationRecord (&al->get_state (), &line);
4208 if (op == Cut || op == Copy) {
4209 /* This operation will involve putting things in the cut buffer, so create an empty
4210 ControlList for each of our source lists to put the cut buffer data in.
4212 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4213 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4216 /* Add all selected points to the relevant copy ControlLists */
4217 framepos_t start = std::numeric_limits<framepos_t>::max();
4218 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4219 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4220 AutomationList::const_iterator j = (*i)->model();
4222 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4224 /* Update earliest MIDI start time in beats */
4225 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4227 /* Update earliest session start time in frames */
4228 start = std::min(start, (*i)->line().session_position(j));
4232 /* Snap start time backwards, so copy/paste is snap aligned. */
4234 if (earliest == Evoral::Beats::max()) {
4235 earliest = Evoral::Beats(); // Weird... don't offset
4237 earliest.round_down_to_beat();
4239 if (start == std::numeric_limits<double>::max()) {
4240 start = 0; // Weird... don't offset
4242 snap_to(start, RoundDownMaybe);
4245 const double line_offset = midi ? earliest.to_double() : start;
4246 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4247 /* Correct this copy list so that it is relative to the earliest
4248 start time, so relative ordering between points is preserved
4249 when copying from several lists and the paste starts at the
4250 earliest copied piece of data. */
4251 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4252 (*j)->when -= line_offset;
4255 /* And add it to the cut buffer */
4256 cut_buffer->add (i->second.copy);
4260 if (op == Delete || op == Cut) {
4261 /* This operation needs to remove things from the main AutomationList, so do that now */
4263 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4264 i->first->freeze ();
4267 /* Remove each selected point from its AutomationList */
4268 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4269 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4270 al->erase ((*i)->model ());
4273 /* Thaw the lists and add undo records for them */
4274 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4275 boost::shared_ptr<AutomationList> al = i->first;
4277 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4282 /** Cut, copy or clear selected automation points.
4283 * @param op Operation (Cut, Copy or Clear)
4286 Editor::cut_copy_midi (CutCopyOp op)
4288 Evoral::Beats earliest = Evoral::Beats::max();
4289 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4290 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4292 if (!mrv->selection().empty()) {
4293 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4295 mrv->cut_copy_clear (op);
4297 /* XXX: not ideal, as there may be more than one track involved in the selection */
4298 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4302 if (!selection->points.empty()) {
4303 cut_copy_points (op, earliest, true);
4304 if (op == Cut || op == Delete) {
4305 selection->clear_points ();
4310 struct lt_playlist {
4311 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4312 return a.playlist < b.playlist;
4316 struct PlaylistMapping {
4318 boost::shared_ptr<Playlist> pl;
4320 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4323 /** Remove `clicked_regionview' */
4325 Editor::remove_clicked_region ()
4327 if (clicked_routeview == 0 || clicked_regionview == 0) {
4331 begin_reversible_command (_("remove region"));
4333 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4335 playlist->clear_changes ();
4336 playlist->clear_owned_changes ();
4337 playlist->remove_region (clicked_regionview->region());
4338 if (Config->get_edit_mode() == Ripple)
4339 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4341 /* We might have removed regions, which alters other regions' layering_index,
4342 so we need to do a recursive diff here.
4344 vector<Command*> cmds;
4345 playlist->rdiff (cmds);
4346 _session->add_commands (cmds);
4348 _session->add_command(new StatefulDiffCommand (playlist));
4349 commit_reversible_command ();
4353 /** Remove the selected regions */
4355 Editor::remove_selected_regions ()
4357 RegionSelection rs = get_regions_from_selection_and_entered ();
4359 if (!_session || rs.empty()) {
4363 list<boost::shared_ptr<Region> > regions_to_remove;
4365 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4366 // we can't just remove the region(s) in this loop because
4367 // this removes them from the RegionSelection, and they thus
4368 // disappear from underneath the iterator, and the ++i above
4369 // SEGVs in a puzzling fashion.
4371 // so, first iterate over the regions to be removed from rs and
4372 // add them to the regions_to_remove list, and then
4373 // iterate over the list to actually remove them.
4375 regions_to_remove.push_back ((*i)->region());
4378 vector<boost::shared_ptr<Playlist> > playlists;
4380 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4382 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4385 // is this check necessary?
4389 /* get_regions_from_selection_and_entered() guarantees that
4390 the playlists involved are unique, so there is no need
4394 playlists.push_back (playlist);
4396 playlist->clear_changes ();
4397 playlist->clear_owned_changes ();
4398 playlist->freeze ();
4399 playlist->remove_region (*rl);
4400 if (Config->get_edit_mode() == Ripple)
4401 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4405 vector<boost::shared_ptr<Playlist> >::iterator pl;
4406 bool in_command = false;
4408 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4411 /* We might have removed regions, which alters other regions' layering_index,
4412 so we need to do a recursive diff here.
4416 begin_reversible_command (_("remove region"));
4419 vector<Command*> cmds;
4420 (*pl)->rdiff (cmds);
4421 _session->add_commands (cmds);
4423 _session->add_command(new StatefulDiffCommand (*pl));
4427 commit_reversible_command ();
4431 /** Cut, copy or clear selected regions.
4432 * @param op Operation (Cut, Copy or Clear)
4435 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4437 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4438 a map when we want ordered access to both elements. i think.
4441 vector<PlaylistMapping> pmap;
4443 framepos_t first_position = max_framepos;
4445 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4446 FreezeList freezelist;
4448 /* get ordering correct before we cut/copy */
4450 rs.sort_by_position_and_track ();
4452 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4454 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4456 if (op == Cut || op == Clear || op == Delete) {
4457 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4460 FreezeList::iterator fl;
4462 // only take state if this is a new playlist.
4463 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4469 if (fl == freezelist.end()) {
4470 pl->clear_changes();
4471 pl->clear_owned_changes ();
4473 freezelist.insert (pl);
4478 TimeAxisView* tv = &(*x)->get_time_axis_view();
4479 vector<PlaylistMapping>::iterator z;
4481 for (z = pmap.begin(); z != pmap.end(); ++z) {
4482 if ((*z).tv == tv) {
4487 if (z == pmap.end()) {
4488 pmap.push_back (PlaylistMapping (tv));
4492 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4494 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4497 /* region not yet associated with a playlist (e.g. unfinished
4504 TimeAxisView& tv = (*x)->get_time_axis_view();
4505 boost::shared_ptr<Playlist> npl;
4506 RegionSelection::iterator tmp;
4513 vector<PlaylistMapping>::iterator z;
4515 for (z = pmap.begin(); z != pmap.end(); ++z) {
4516 if ((*z).tv == &tv) {
4521 assert (z != pmap.end());
4524 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4532 boost::shared_ptr<Region> r = (*x)->region();
4533 boost::shared_ptr<Region> _xx;
4539 pl->remove_region (r);
4540 if (Config->get_edit_mode() == Ripple)
4541 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4545 _xx = RegionFactory::create (r);
4546 npl->add_region (_xx, r->position() - first_position);
4547 pl->remove_region (r);
4548 if (Config->get_edit_mode() == Ripple)
4549 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4553 /* copy region before adding, so we're not putting same object into two different playlists */
4554 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4558 pl->remove_region (r);
4559 if (Config->get_edit_mode() == Ripple)
4560 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4569 list<boost::shared_ptr<Playlist> > foo;
4571 /* the pmap is in the same order as the tracks in which selected regions occurred */
4573 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4576 foo.push_back ((*i).pl);
4581 cut_buffer->set (foo);
4585 _last_cut_copy_source_track = 0;
4587 _last_cut_copy_source_track = pmap.front().tv;
4591 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4594 /* We might have removed regions, which alters other regions' layering_index,
4595 so we need to do a recursive diff here.
4597 vector<Command*> cmds;
4598 (*pl)->rdiff (cmds);
4599 _session->add_commands (cmds);
4601 _session->add_command (new StatefulDiffCommand (*pl));
4606 Editor::cut_copy_ranges (CutCopyOp op)
4608 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4610 /* Sort the track selection now, so that it if is used, the playlists
4611 selected by the calls below to cut_copy_clear are in the order that
4612 their tracks appear in the editor. This makes things like paste
4613 of ranges work properly.
4616 sort_track_selection (ts);
4619 if (!entered_track) {
4622 ts.push_back (entered_track);
4625 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4626 (*i)->cut_copy_clear (*selection, op);
4631 Editor::paste (float times, bool from_context)
4633 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4635 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4639 Editor::mouse_paste ()
4644 if (!mouse_frame (where, ignored)) {
4649 paste_internal (where, 1);
4653 Editor::paste_internal (framepos_t position, float times)
4655 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4657 if (cut_buffer->empty(internal_editing())) {
4661 if (position == max_framepos) {
4662 position = get_preferred_edit_position();
4663 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4666 if (position == last_paste_pos) {
4667 /* repeated paste in the same position */
4670 /* paste in new location, reset repeated paste state */
4672 last_paste_pos = position;
4675 /* get everything in the correct order */
4678 if (!selection->tracks.empty()) {
4679 /* If there is a track selection, paste into exactly those tracks and
4680 only those tracks. This allows the user to be explicit and override
4681 the below "do the reasonable thing" logic. */
4682 ts = selection->tracks.filter_to_unique_playlists ();
4683 sort_track_selection (ts);
4685 /* Figure out which track to base the paste at. */
4686 TimeAxisView* base_track = NULL;
4687 if (_edit_point == Editing::EditAtMouse && entered_track) {
4688 /* With the mouse edit point, paste onto the track under the mouse. */
4689 base_track = entered_track;
4690 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4691 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4692 base_track = &entered_regionview->get_time_axis_view();
4693 } else if (_last_cut_copy_source_track) {
4694 /* Paste to the track that the cut/copy came from (see mantis #333). */
4695 base_track = _last_cut_copy_source_track;
4697 /* This is "impossible" since we've copied... well, do nothing. */
4701 /* Walk up to parent if necessary, so base track is a route. */
4702 while (base_track->get_parent()) {
4703 base_track = base_track->get_parent();
4706 /* Add base track and all tracks below it. The paste logic will select
4707 the appropriate object types from the cut buffer in relative order. */
4708 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4709 if ((*i)->order() >= base_track->order()) {
4714 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4715 sort_track_selection (ts);
4717 /* Add automation children of each track in order, for pasting several lines. */
4718 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4719 /* Add any automation children for pasting several lines */
4720 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4725 typedef RouteTimeAxisView::AutomationTracks ATracks;
4726 const ATracks& atracks = rtv->automation_tracks();
4727 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4728 i = ts.insert(i, a->second.get());
4733 /* We now have a list of trackviews starting at base_track, including
4734 automation children, in the order shown in the editor, e.g. R1,
4735 R1.A1, R1.A2, R2, R2.A1, ... */
4738 begin_reversible_command (Operations::paste);
4740 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4741 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4742 /* Only one line copied, and one automation track selected. Do a
4743 "greedy" paste from one automation type to another. */
4745 PasteContext ctx(paste_count, times, ItemCounts(), true);
4746 ts.front()->paste (position, *cut_buffer, ctx);
4750 /* Paste into tracks */
4752 PasteContext ctx(paste_count, times, ItemCounts(), false);
4753 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4754 (*i)->paste (position, *cut_buffer, ctx);
4758 commit_reversible_command ();
4762 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4764 if (regions.empty ()) {
4768 boost::shared_ptr<Playlist> playlist;
4769 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4770 RegionSelection foo;
4772 framepos_t const start_frame = regions.start ();
4773 framepos_t const end_frame = regions.end_frame ();
4774 framecnt_t const gap = end_frame - start_frame + 1;
4776 begin_reversible_command (Operations::duplicate_region);
4778 selection->clear_regions ();
4780 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4782 boost::shared_ptr<Region> r ((*i)->region());
4784 TimeAxisView& tv = (*i)->get_time_axis_view();
4785 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4786 latest_regionviews.clear ();
4787 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4789 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4790 playlist = (*i)->region()->playlist();
4791 playlist->clear_changes ();
4792 playlist->duplicate (r, position, gap, times);
4793 _session->add_command(new StatefulDiffCommand (playlist));
4797 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4801 selection->set (foo);
4804 commit_reversible_command ();
4808 Editor::duplicate_selection (float times)
4810 if (selection->time.empty() || selection->tracks.empty()) {
4814 boost::shared_ptr<Playlist> playlist;
4816 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4818 bool in_command = false;
4820 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4821 if ((playlist = (*i)->playlist()) == 0) {
4824 playlist->clear_changes ();
4826 if (clicked_selection) {
4827 playlist->duplicate_range (selection->time[clicked_selection], times);
4829 playlist->duplicate_ranges (selection->time, times);
4833 begin_reversible_command (_("duplicate range selection"));
4836 _session->add_command (new StatefulDiffCommand (playlist));
4841 // now "move" range selection to after the current range selection
4842 framecnt_t distance = 0;
4844 if (clicked_selection) {
4845 distance = selection->time[clicked_selection].end -
4846 selection->time[clicked_selection].start;
4848 distance = selection->time.end_frame() - selection->time.start();
4851 selection->move_time (distance);
4853 commit_reversible_command ();
4857 /** Reset all selected points to the relevant default value */
4859 Editor::reset_point_selection ()
4861 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4862 ARDOUR::AutomationList::iterator j = (*i)->model ();
4863 (*j)->value = (*i)->line().the_list()->default_value ();
4868 Editor::center_playhead ()
4870 float const page = _visible_canvas_width * samples_per_pixel;
4871 center_screen_internal (playhead_cursor->current_frame (), page);
4875 Editor::center_edit_point ()
4877 float const page = _visible_canvas_width * samples_per_pixel;
4878 center_screen_internal (get_preferred_edit_position(), page);
4881 /** Caller must begin and commit a reversible command */
4883 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4885 playlist->clear_changes ();
4887 _session->add_command (new StatefulDiffCommand (playlist));
4891 Editor::nudge_track (bool use_edit, bool forwards)
4893 boost::shared_ptr<Playlist> playlist;
4894 framepos_t distance;
4895 framepos_t next_distance;
4899 start = get_preferred_edit_position();
4904 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4908 if (selection->tracks.empty()) {
4912 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4913 bool in_command = false;
4915 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4917 if ((playlist = (*i)->playlist()) == 0) {
4921 playlist->clear_changes ();
4922 playlist->clear_owned_changes ();
4924 playlist->nudge_after (start, distance, forwards);
4927 begin_reversible_command (_("nudge track"));
4930 vector<Command*> cmds;
4932 playlist->rdiff (cmds);
4933 _session->add_commands (cmds);
4935 _session->add_command (new StatefulDiffCommand (playlist));
4939 commit_reversible_command ();
4944 Editor::remove_last_capture ()
4946 vector<string> choices;
4953 if (Config->get_verify_remove_last_capture()) {
4954 prompt = _("Do you really want to destroy the last capture?"
4955 "\n(This is destructive and cannot be undone)");
4957 choices.push_back (_("No, do nothing."));
4958 choices.push_back (_("Yes, destroy it."));
4960 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4962 if (prompter.run () == 1) {
4963 _session->remove_last_capture ();
4964 _regions->redisplay ();
4968 _session->remove_last_capture();
4969 _regions->redisplay ();
4974 Editor::normalize_region ()
4980 RegionSelection rs = get_regions_from_selection_and_entered ();
4986 NormalizeDialog dialog (rs.size() > 1);
4988 if (dialog.run () == RESPONSE_CANCEL) {
4992 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4995 /* XXX: should really only count audio regions here */
4996 int const regions = rs.size ();
4998 /* Make a list of the selected audio regions' maximum amplitudes, and also
4999 obtain the maximum amplitude of them all.
5001 list<double> max_amps;
5003 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5004 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5006 dialog.descend (1.0 / regions);
5007 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5010 /* the user cancelled the operation */
5014 max_amps.push_back (a);
5015 max_amp = max (max_amp, a);
5020 list<double>::const_iterator a = max_amps.begin ();
5021 bool in_command = false;
5023 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5024 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5029 arv->region()->clear_changes ();
5031 double const amp = dialog.normalize_individually() ? *a : max_amp;
5033 arv->audio_region()->normalize (amp, dialog.target ());
5036 begin_reversible_command (_("normalize"));
5039 _session->add_command (new StatefulDiffCommand (arv->region()));
5045 commit_reversible_command ();
5051 Editor::reset_region_scale_amplitude ()
5057 RegionSelection rs = get_regions_from_selection_and_entered ();
5063 bool in_command = false;
5065 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5066 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5069 arv->region()->clear_changes ();
5070 arv->audio_region()->set_scale_amplitude (1.0f);
5073 begin_reversible_command ("reset gain");
5076 _session->add_command (new StatefulDiffCommand (arv->region()));
5080 commit_reversible_command ();
5085 Editor::adjust_region_gain (bool up)
5087 RegionSelection rs = get_regions_from_selection_and_entered ();
5089 if (!_session || rs.empty()) {
5093 bool in_command = false;
5095 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5096 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5101 arv->region()->clear_changes ();
5103 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5111 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5114 begin_reversible_command ("adjust region gain");
5117 _session->add_command (new StatefulDiffCommand (arv->region()));
5121 commit_reversible_command ();
5127 Editor::reverse_region ()
5133 Reverse rev (*_session);
5134 apply_filter (rev, _("reverse regions"));
5138 Editor::strip_region_silence ()
5144 RegionSelection rs = get_regions_from_selection_and_entered ();
5150 std::list<RegionView*> audio_only;
5152 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5153 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5155 audio_only.push_back (arv);
5159 assert (!audio_only.empty());
5161 StripSilenceDialog d (_session, audio_only);
5162 int const r = d.run ();
5166 if (r == Gtk::RESPONSE_OK) {
5167 ARDOUR::AudioIntervalMap silences;
5168 d.silences (silences);
5169 StripSilence s (*_session, silences, d.fade_length());
5171 apply_filter (s, _("strip silence"), &d);
5176 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5178 Evoral::Sequence<Evoral::Beats>::Notes selected;
5179 mrv.selection_as_notelist (selected, true);
5181 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5182 v.push_back (selected);
5184 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5185 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5187 return op (mrv.midi_region()->model(), pos_beats, v);
5191 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5197 bool in_command = false;
5199 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5200 RegionSelection::const_iterator tmp = r;
5203 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5206 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5209 begin_reversible_command (op.name ());
5213 _session->add_command (cmd);
5221 commit_reversible_command ();
5226 Editor::fork_region ()
5228 RegionSelection rs = get_regions_from_selection_and_entered ();
5234 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5235 bool in_command = false;
5239 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5240 RegionSelection::iterator tmp = r;
5243 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5247 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5248 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5249 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5252 begin_reversible_command (_("Fork Region(s)"));
5255 playlist->clear_changes ();
5256 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5257 _session->add_command(new StatefulDiffCommand (playlist));
5259 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5267 commit_reversible_command ();
5272 Editor::quantize_region ()
5275 quantize_regions(get_regions_from_selection_and_entered ());
5280 Editor::quantize_regions (const RegionSelection& rs)
5282 if (rs.n_midi_regions() == 0) {
5286 if (!quantize_dialog) {
5287 quantize_dialog = new QuantizeDialog (*this);
5290 quantize_dialog->present ();
5291 const int r = quantize_dialog->run ();
5292 quantize_dialog->hide ();
5294 if (r == Gtk::RESPONSE_OK) {
5295 Quantize quant (quantize_dialog->snap_start(),
5296 quantize_dialog->snap_end(),
5297 quantize_dialog->start_grid_size(),
5298 quantize_dialog->end_grid_size(),
5299 quantize_dialog->strength(),
5300 quantize_dialog->swing(),
5301 quantize_dialog->threshold());
5303 apply_midi_note_edit_op (quant, rs);
5308 Editor::legatize_region (bool shrink_only)
5311 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5316 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5318 if (rs.n_midi_regions() == 0) {
5322 Legatize legatize(shrink_only);
5323 apply_midi_note_edit_op (legatize, rs);
5327 Editor::transform_region ()
5330 transform_regions(get_regions_from_selection_and_entered ());
5335 Editor::transform_regions (const RegionSelection& rs)
5337 if (rs.n_midi_regions() == 0) {
5344 const int r = td.run();
5347 if (r == Gtk::RESPONSE_OK) {
5348 Transform transform(td.get());
5349 apply_midi_note_edit_op(transform, rs);
5354 Editor::transpose_region ()
5357 transpose_regions(get_regions_from_selection_and_entered ());
5362 Editor::transpose_regions (const RegionSelection& rs)
5364 if (rs.n_midi_regions() == 0) {
5369 int const r = d.run ();
5371 if (r == RESPONSE_ACCEPT) {
5372 Transpose transpose(d.semitones ());
5373 apply_midi_note_edit_op (transpose, rs);
5378 Editor::insert_patch_change (bool from_context)
5380 RegionSelection rs = get_regions_from_selection_and_entered ();
5386 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5388 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5389 there may be more than one, but the PatchChangeDialog can only offer
5390 one set of patch menus.
5392 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5394 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5395 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5397 if (d.run() == RESPONSE_CANCEL) {
5401 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5402 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5404 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5405 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5412 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5414 RegionSelection rs = get_regions_from_selection_and_entered ();
5420 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5421 bool in_command = false;
5426 int const N = rs.size ();
5428 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5429 RegionSelection::iterator tmp = r;
5432 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5434 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5437 progress->descend (1.0 / N);
5440 if (arv->audio_region()->apply (filter, progress) == 0) {
5442 playlist->clear_changes ();
5443 playlist->clear_owned_changes ();
5446 begin_reversible_command (command);
5450 if (filter.results.empty ()) {
5452 /* no regions returned; remove the old one */
5453 playlist->remove_region (arv->region ());
5457 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5459 /* first region replaces the old one */
5460 playlist->replace_region (arv->region(), *res, (*res)->position());
5464 while (res != filter.results.end()) {
5465 playlist->add_region (*res, (*res)->position());
5471 /* We might have removed regions, which alters other regions' layering_index,
5472 so we need to do a recursive diff here.
5474 vector<Command*> cmds;
5475 playlist->rdiff (cmds);
5476 _session->add_commands (cmds);
5478 _session->add_command(new StatefulDiffCommand (playlist));
5482 progress->ascend ();
5491 commit_reversible_command ();
5496 Editor::external_edit_region ()
5502 Editor::reset_region_gain_envelopes ()
5504 RegionSelection rs = get_regions_from_selection_and_entered ();
5506 if (!_session || rs.empty()) {
5510 bool in_command = false;
5512 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5513 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5515 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5516 XMLNode& before (alist->get_state());
5518 arv->audio_region()->set_default_envelope ();
5521 begin_reversible_command (_("reset region gain"));
5524 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5529 commit_reversible_command ();
5534 Editor::set_region_gain_visibility (RegionView* rv)
5536 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5538 arv->update_envelope_visibility();
5543 Editor::set_gain_envelope_visibility ()
5549 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5550 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5552 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5558 Editor::toggle_gain_envelope_active ()
5560 if (_ignore_region_action) {
5564 RegionSelection rs = get_regions_from_selection_and_entered ();
5566 if (!_session || rs.empty()) {
5570 bool in_command = false;
5572 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5573 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5575 arv->region()->clear_changes ();
5576 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5579 begin_reversible_command (_("region gain envelope active"));
5582 _session->add_command (new StatefulDiffCommand (arv->region()));
5587 commit_reversible_command ();
5592 Editor::toggle_region_lock ()
5594 if (_ignore_region_action) {
5598 RegionSelection rs = get_regions_from_selection_and_entered ();
5600 if (!_session || rs.empty()) {
5604 begin_reversible_command (_("toggle region lock"));
5606 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5607 (*i)->region()->clear_changes ();
5608 (*i)->region()->set_locked (!(*i)->region()->locked());
5609 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5612 commit_reversible_command ();
5616 Editor::toggle_region_video_lock ()
5618 if (_ignore_region_action) {
5622 RegionSelection rs = get_regions_from_selection_and_entered ();
5624 if (!_session || rs.empty()) {
5628 begin_reversible_command (_("Toggle Video Lock"));
5630 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5631 (*i)->region()->clear_changes ();
5632 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5633 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5636 commit_reversible_command ();
5640 Editor::toggle_region_lock_style ()
5642 if (_ignore_region_action) {
5646 RegionSelection rs = get_regions_from_selection_and_entered ();
5648 if (!_session || rs.empty()) {
5652 begin_reversible_command (_("region lock style"));
5654 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5655 (*i)->region()->clear_changes ();
5656 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5657 (*i)->region()->set_position_lock_style (ns);
5658 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5661 commit_reversible_command ();
5665 Editor::toggle_opaque_region ()
5667 if (_ignore_region_action) {
5671 RegionSelection rs = get_regions_from_selection_and_entered ();
5673 if (!_session || rs.empty()) {
5677 begin_reversible_command (_("change region opacity"));
5679 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5680 (*i)->region()->clear_changes ();
5681 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5682 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5685 commit_reversible_command ();
5689 Editor::toggle_record_enable ()
5691 bool new_state = false;
5693 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5694 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5697 if (!rtav->is_track())
5701 new_state = !rtav->track()->record_enabled();
5705 rtav->track()->set_record_enabled (new_state, Controllable::UseGroup);
5710 Editor::toggle_solo ()
5712 bool new_state = false;
5714 boost::shared_ptr<RouteList> rl (new RouteList);
5716 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5717 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5724 new_state = !rtav->route()->soloed ();
5728 rl->push_back (rtav->route());
5731 _session->set_solo (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
5735 Editor::toggle_mute ()
5737 bool new_state = false;
5739 boost::shared_ptr<RouteList> rl (new RouteList);
5741 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5742 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5749 new_state = !rtav->route()->muted();
5753 rl->push_back (rtav->route());
5756 _session->set_mute (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
5760 Editor::toggle_solo_isolate ()
5766 Editor::fade_range ()
5768 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5770 begin_reversible_command (_("fade range"));
5772 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5773 (*i)->fade_range (selection->time);
5776 commit_reversible_command ();
5781 Editor::set_fade_length (bool in)
5783 RegionSelection rs = get_regions_from_selection_and_entered ();
5789 /* we need a region to measure the offset from the start */
5791 RegionView* rv = rs.front ();
5793 framepos_t pos = get_preferred_edit_position();
5797 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5798 /* edit point is outside the relevant region */
5803 if (pos <= rv->region()->position()) {
5807 len = pos - rv->region()->position();
5808 cmd = _("set fade in length");
5810 if (pos >= rv->region()->last_frame()) {
5814 len = rv->region()->last_frame() - pos;
5815 cmd = _("set fade out length");
5818 bool in_command = false;
5820 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5821 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5827 boost::shared_ptr<AutomationList> alist;
5829 alist = tmp->audio_region()->fade_in();
5831 alist = tmp->audio_region()->fade_out();
5834 XMLNode &before = alist->get_state();
5837 tmp->audio_region()->set_fade_in_length (len);
5838 tmp->audio_region()->set_fade_in_active (true);
5840 tmp->audio_region()->set_fade_out_length (len);
5841 tmp->audio_region()->set_fade_out_active (true);
5845 begin_reversible_command (cmd);
5848 XMLNode &after = alist->get_state();
5849 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5853 commit_reversible_command ();
5858 Editor::set_fade_in_shape (FadeShape shape)
5860 RegionSelection rs = get_regions_from_selection_and_entered ();
5865 bool in_command = false;
5867 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5868 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5874 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5875 XMLNode &before = alist->get_state();
5877 tmp->audio_region()->set_fade_in_shape (shape);
5880 begin_reversible_command (_("set fade in shape"));
5883 XMLNode &after = alist->get_state();
5884 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5888 commit_reversible_command ();
5893 Editor::set_fade_out_shape (FadeShape shape)
5895 RegionSelection rs = get_regions_from_selection_and_entered ();
5900 bool in_command = false;
5902 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5903 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5909 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5910 XMLNode &before = alist->get_state();
5912 tmp->audio_region()->set_fade_out_shape (shape);
5915 begin_reversible_command (_("set fade out shape"));
5918 XMLNode &after = alist->get_state();
5919 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5923 commit_reversible_command ();
5928 Editor::set_fade_in_active (bool yn)
5930 RegionSelection rs = get_regions_from_selection_and_entered ();
5935 bool in_command = false;
5937 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5938 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5945 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5947 ar->clear_changes ();
5948 ar->set_fade_in_active (yn);
5951 begin_reversible_command (_("set fade in active"));
5954 _session->add_command (new StatefulDiffCommand (ar));
5958 commit_reversible_command ();
5963 Editor::set_fade_out_active (bool yn)
5965 RegionSelection rs = get_regions_from_selection_and_entered ();
5970 bool in_command = false;
5972 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5973 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5979 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5981 ar->clear_changes ();
5982 ar->set_fade_out_active (yn);
5985 begin_reversible_command (_("set fade out active"));
5988 _session->add_command(new StatefulDiffCommand (ar));
5992 commit_reversible_command ();
5997 Editor::toggle_region_fades (int dir)
5999 if (_ignore_region_action) {
6003 boost::shared_ptr<AudioRegion> ar;
6006 RegionSelection rs = get_regions_from_selection_and_entered ();
6012 RegionSelection::iterator i;
6013 for (i = rs.begin(); i != rs.end(); ++i) {
6014 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6016 yn = ar->fade_out_active ();
6018 yn = ar->fade_in_active ();
6024 if (i == rs.end()) {
6028 /* XXX should this undo-able? */
6029 bool in_command = false;
6031 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6032 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6035 ar->clear_changes ();
6037 if (dir == 1 || dir == 0) {
6038 ar->set_fade_in_active (!yn);
6041 if (dir == -1 || dir == 0) {
6042 ar->set_fade_out_active (!yn);
6045 begin_reversible_command (_("toggle fade active"));
6048 _session->add_command(new StatefulDiffCommand (ar));
6052 commit_reversible_command ();
6057 /** Update region fade visibility after its configuration has been changed */
6059 Editor::update_region_fade_visibility ()
6061 bool _fade_visibility = _session->config.get_show_region_fades ();
6063 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6064 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6066 if (_fade_visibility) {
6067 v->audio_view()->show_all_fades ();
6069 v->audio_view()->hide_all_fades ();
6076 Editor::set_edit_point ()
6081 if (!mouse_frame (where, ignored)) {
6087 if (selection->markers.empty()) {
6089 mouse_add_new_marker (where);
6094 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6097 loc->move_to (where);
6103 Editor::set_playhead_cursor ()
6105 if (entered_marker) {
6106 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6111 if (!mouse_frame (where, ignored)) {
6118 _session->request_locate (where, _session->transport_rolling());
6122 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6123 cancel_time_selection();
6128 Editor::split_region ()
6130 if (_drags->active ()) {
6134 //if a range is selected, separate it
6135 if ( !selection->time.empty()) {
6136 separate_regions_between (selection->time);
6140 //if no range was selected, try to find some regions to split
6141 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6143 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6145 framepos_t where = get_preferred_edit_position ();
6151 split_regions_at (where, rs);
6155 struct EditorOrderRouteSorter {
6156 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6157 return a->order_key () < b->order_key ();
6162 Editor::select_next_route()
6164 if (selection->tracks.empty()) {
6165 selection->set (track_views.front());
6169 TimeAxisView* current = selection->tracks.front();
6173 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6174 if (*i == current) {
6176 if (i != track_views.end()) {
6179 current = (*(track_views.begin()));
6180 //selection->set (*(track_views.begin()));
6185 rui = dynamic_cast<RouteUI *>(current);
6186 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6188 selection->set(current);
6190 ensure_time_axis_view_is_visible (*current, false);
6194 Editor::select_prev_route()
6196 if (selection->tracks.empty()) {
6197 selection->set (track_views.front());
6201 TimeAxisView* current = selection->tracks.front();
6205 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6206 if (*i == current) {
6208 if (i != track_views.rend()) {
6211 current = *(track_views.rbegin());
6216 rui = dynamic_cast<RouteUI *>(current);
6217 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6219 selection->set (current);
6221 ensure_time_axis_view_is_visible (*current, false);
6225 Editor::set_loop_from_selection (bool play)
6227 if (_session == 0) {
6231 framepos_t start, end;
6232 if (!get_selection_extents ( start, end))
6235 set_loop_range (start, end, _("set loop range from selection"));
6238 _session->request_play_loop (true, true);
6243 Editor::set_loop_from_region (bool play)
6245 framepos_t start, end;
6246 if (!get_selection_extents ( start, end))
6249 set_loop_range (start, end, _("set loop range from region"));
6252 _session->request_locate (start, true);
6253 _session->request_play_loop (true);
6258 Editor::set_punch_from_selection ()
6260 if (_session == 0) {
6264 framepos_t start, end;
6265 if (!get_selection_extents ( start, end))
6268 set_punch_range (start, end, _("set punch range from selection"));
6272 Editor::set_session_extents_from_selection ()
6274 if (_session == 0) {
6278 framepos_t start, end;
6279 if (!get_selection_extents ( start, end))
6283 if ((loc = _session->locations()->session_range_location()) == 0) {
6284 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6286 XMLNode &before = loc->get_state();
6288 _session->set_session_extents ( start, end );
6290 XMLNode &after = loc->get_state();
6292 begin_reversible_command (_("set session start/end from selection"));
6294 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6296 commit_reversible_command ();
6301 Editor::set_punch_start_from_edit_point ()
6305 framepos_t start = 0;
6306 framepos_t end = max_framepos;
6308 //use the existing punch end, if any
6309 Location* tpl = transport_punch_location();
6314 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6315 start = _session->audible_frame();
6317 start = get_preferred_edit_position();
6320 //snap the selection start/end
6323 //if there's not already a sensible selection endpoint, go "forever"
6324 if ( start > end ) {
6328 set_punch_range (start, end, _("set punch start from EP"));
6334 Editor::set_punch_end_from_edit_point ()
6338 framepos_t start = 0;
6339 framepos_t end = max_framepos;
6341 //use the existing punch start, if any
6342 Location* tpl = transport_punch_location();
6344 start = tpl->start();
6347 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6348 end = _session->audible_frame();
6350 end = get_preferred_edit_position();
6353 //snap the selection start/end
6356 set_punch_range (start, end, _("set punch end from EP"));
6362 Editor::set_loop_start_from_edit_point ()
6366 framepos_t start = 0;
6367 framepos_t end = max_framepos;
6369 //use the existing loop end, if any
6370 Location* tpl = transport_loop_location();
6375 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6376 start = _session->audible_frame();
6378 start = get_preferred_edit_position();
6381 //snap the selection start/end
6384 //if there's not already a sensible selection endpoint, go "forever"
6385 if ( start > end ) {
6389 set_loop_range (start, end, _("set loop start from EP"));
6395 Editor::set_loop_end_from_edit_point ()
6399 framepos_t start = 0;
6400 framepos_t end = max_framepos;
6402 //use the existing loop start, if any
6403 Location* tpl = transport_loop_location();
6405 start = tpl->start();
6408 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6409 end = _session->audible_frame();
6411 end = get_preferred_edit_position();
6414 //snap the selection start/end
6417 set_loop_range (start, end, _("set loop end from EP"));
6422 Editor::set_punch_from_region ()
6424 framepos_t start, end;
6425 if (!get_selection_extents ( start, end))
6428 set_punch_range (start, end, _("set punch range from region"));
6432 Editor::pitch_shift_region ()
6434 RegionSelection rs = get_regions_from_selection_and_entered ();
6436 RegionSelection audio_rs;
6437 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6438 if (dynamic_cast<AudioRegionView*> (*i)) {
6439 audio_rs.push_back (*i);
6443 if (audio_rs.empty()) {
6447 pitch_shift (audio_rs, 1.2);
6451 Editor::set_tempo_from_region ()
6453 RegionSelection rs = get_regions_from_selection_and_entered ();
6455 if (!_session || rs.empty()) {
6459 RegionView* rv = rs.front();
6461 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6465 Editor::use_range_as_bar ()
6467 framepos_t start, end;
6468 if (get_edit_op_range (start, end)) {
6469 define_one_bar (start, end);
6474 Editor::define_one_bar (framepos_t start, framepos_t end)
6476 framepos_t length = end - start;
6478 const Meter& m (_session->tempo_map().meter_at (start));
6480 /* length = 1 bar */
6482 /* now we want frames per beat.
6483 we have frames per bar, and beats per bar, so ...
6486 /* XXXX METER MATH */
6488 double frames_per_beat = length / m.divisions_per_bar();
6490 /* beats per minute = */
6492 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6494 /* now decide whether to:
6496 (a) set global tempo
6497 (b) add a new tempo marker
6501 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6503 bool do_global = false;
6505 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6507 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6508 at the start, or create a new marker
6511 vector<string> options;
6512 options.push_back (_("Cancel"));
6513 options.push_back (_("Add new marker"));
6514 options.push_back (_("Set global tempo"));
6517 _("Define one bar"),
6518 _("Do you want to set the global tempo or add a new tempo marker?"),
6522 c.set_default_response (2);
6538 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6539 if the marker is at the region starter, change it, otherwise add
6544 begin_reversible_command (_("set tempo from region"));
6545 XMLNode& before (_session->tempo_map().get_state());
6548 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6549 } else if (t.frame() == start) {
6550 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6552 Timecode::BBT_Time bbt;
6553 _session->tempo_map().bbt_time (start, bbt);
6554 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6557 XMLNode& after (_session->tempo_map().get_state());
6559 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6560 commit_reversible_command ();
6564 Editor::split_region_at_transients ()
6566 AnalysisFeatureList positions;
6568 RegionSelection rs = get_regions_from_selection_and_entered ();
6570 if (!_session || rs.empty()) {
6574 begin_reversible_command (_("split regions"));
6576 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6578 RegionSelection::iterator tmp;
6583 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6586 ar->transients (positions);
6587 split_region_at_points ((*i)->region(), positions, true);
6594 commit_reversible_command ();
6599 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6601 bool use_rhythmic_rodent = false;
6603 boost::shared_ptr<Playlist> pl = r->playlist();
6605 list<boost::shared_ptr<Region> > new_regions;
6611 if (positions.empty()) {
6615 if (positions.size() > 20 && can_ferret) {
6616 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);
6617 MessageDialog msg (msgstr,
6620 Gtk::BUTTONS_OK_CANCEL);
6623 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6624 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6626 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6629 msg.set_title (_("Excessive split?"));
6632 int response = msg.run();
6638 case RESPONSE_APPLY:
6639 use_rhythmic_rodent = true;
6646 if (use_rhythmic_rodent) {
6647 show_rhythm_ferret ();
6651 AnalysisFeatureList::const_iterator x;
6653 pl->clear_changes ();
6654 pl->clear_owned_changes ();
6656 x = positions.begin();
6658 if (x == positions.end()) {
6663 pl->remove_region (r);
6667 framepos_t rstart = r->first_frame ();
6668 framepos_t rend = r->last_frame ();
6670 while (x != positions.end()) {
6672 /* deal with positons that are out of scope of present region bounds */
6673 if (*x <= rstart || *x > rend) {
6678 /* file start = original start + how far we from the initial position ? */
6680 framepos_t file_start = r->start() + pos;
6682 /* length = next position - current position */
6684 framepos_t len = (*x) - pos - rstart;
6686 /* XXX we do we really want to allow even single-sample regions?
6687 * shouldn't we have some kind of lower limit on region size?
6696 if (RegionFactory::region_name (new_name, r->name())) {
6700 /* do NOT announce new regions 1 by one, just wait till they are all done */
6704 plist.add (ARDOUR::Properties::start, file_start);
6705 plist.add (ARDOUR::Properties::length, len);
6706 plist.add (ARDOUR::Properties::name, new_name);
6707 plist.add (ARDOUR::Properties::layer, 0);
6708 // TODO set transients_offset
6710 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6711 /* because we set annouce to false, manually add the new region to the
6714 RegionFactory::map_add (nr);
6716 pl->add_region (nr, rstart + pos);
6719 new_regions.push_front(nr);
6728 RegionFactory::region_name (new_name, r->name());
6730 /* Add the final region */
6733 plist.add (ARDOUR::Properties::start, r->start() + pos);
6734 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6735 plist.add (ARDOUR::Properties::name, new_name);
6736 plist.add (ARDOUR::Properties::layer, 0);
6738 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6739 /* because we set annouce to false, manually add the new region to the
6742 RegionFactory::map_add (nr);
6743 pl->add_region (nr, r->position() + pos);
6746 new_regions.push_front(nr);
6751 /* We might have removed regions, which alters other regions' layering_index,
6752 so we need to do a recursive diff here.
6754 vector<Command*> cmds;
6756 _session->add_commands (cmds);
6758 _session->add_command (new StatefulDiffCommand (pl));
6762 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6763 set_selected_regionview_from_region_list ((*i), Selection::Add);
6769 Editor::place_transient()
6775 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6781 framepos_t where = get_preferred_edit_position();
6783 begin_reversible_command (_("place transient"));
6785 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6786 (*r)->region()->add_transient(where);
6789 commit_reversible_command ();
6793 Editor::remove_transient(ArdourCanvas::Item* item)
6799 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6802 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6803 _arv->remove_transient (*(float*) _line->get_data ("position"));
6807 Editor::snap_regions_to_grid ()
6809 list <boost::shared_ptr<Playlist > > used_playlists;
6811 RegionSelection rs = get_regions_from_selection_and_entered ();
6813 if (!_session || rs.empty()) {
6817 begin_reversible_command (_("snap regions to grid"));
6819 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6821 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6823 if (!pl->frozen()) {
6824 /* we haven't seen this playlist before */
6826 /* remember used playlists so we can thaw them later */
6827 used_playlists.push_back(pl);
6831 framepos_t start_frame = (*r)->region()->first_frame ();
6832 snap_to (start_frame);
6833 (*r)->region()->set_position (start_frame);
6836 while (used_playlists.size() > 0) {
6837 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6839 used_playlists.pop_front();
6842 commit_reversible_command ();
6846 Editor::close_region_gaps ()
6848 list <boost::shared_ptr<Playlist > > used_playlists;
6850 RegionSelection rs = get_regions_from_selection_and_entered ();
6852 if (!_session || rs.empty()) {
6856 Dialog dialog (_("Close Region Gaps"));
6859 table.set_spacings (12);
6860 table.set_border_width (12);
6861 Label* l = manage (left_aligned_label (_("Crossfade length")));
6862 table.attach (*l, 0, 1, 0, 1);
6864 SpinButton spin_crossfade (1, 0);
6865 spin_crossfade.set_range (0, 15);
6866 spin_crossfade.set_increments (1, 1);
6867 spin_crossfade.set_value (5);
6868 table.attach (spin_crossfade, 1, 2, 0, 1);
6870 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6872 l = manage (left_aligned_label (_("Pull-back length")));
6873 table.attach (*l, 0, 1, 1, 2);
6875 SpinButton spin_pullback (1, 0);
6876 spin_pullback.set_range (0, 100);
6877 spin_pullback.set_increments (1, 1);
6878 spin_pullback.set_value(30);
6879 table.attach (spin_pullback, 1, 2, 1, 2);
6881 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6883 dialog.get_vbox()->pack_start (table);
6884 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6885 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6888 if (dialog.run () == RESPONSE_CANCEL) {
6892 framepos_t crossfade_len = spin_crossfade.get_value();
6893 framepos_t pull_back_frames = spin_pullback.get_value();
6895 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6896 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6898 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6900 begin_reversible_command (_("close region gaps"));
6903 boost::shared_ptr<Region> last_region;
6905 rs.sort_by_position_and_track();
6907 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6909 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6911 if (!pl->frozen()) {
6912 /* we haven't seen this playlist before */
6914 /* remember used playlists so we can thaw them later */
6915 used_playlists.push_back(pl);
6919 framepos_t position = (*r)->region()->position();
6921 if (idx == 0 || position < last_region->position()){
6922 last_region = (*r)->region();
6927 (*r)->region()->trim_front( (position - pull_back_frames));
6928 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6930 last_region = (*r)->region();
6935 while (used_playlists.size() > 0) {
6936 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6938 used_playlists.pop_front();
6941 commit_reversible_command ();
6945 Editor::tab_to_transient (bool forward)
6947 AnalysisFeatureList positions;
6949 RegionSelection rs = get_regions_from_selection_and_entered ();
6955 framepos_t pos = _session->audible_frame ();
6957 if (!selection->tracks.empty()) {
6959 /* don't waste time searching for transients in duplicate playlists.
6962 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6964 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6966 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6969 boost::shared_ptr<Track> tr = rtv->track();
6971 boost::shared_ptr<Playlist> pl = tr->playlist ();
6973 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6976 positions.push_back (result);
6989 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6990 (*r)->region()->get_transients (positions);
6994 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6997 AnalysisFeatureList::iterator x;
6999 for (x = positions.begin(); x != positions.end(); ++x) {
7005 if (x != positions.end ()) {
7006 _session->request_locate (*x);
7010 AnalysisFeatureList::reverse_iterator x;
7012 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7018 if (x != positions.rend ()) {
7019 _session->request_locate (*x);
7025 Editor::playhead_forward_to_grid ()
7031 framepos_t pos = playhead_cursor->current_frame ();
7032 if (pos < max_framepos - 1) {
7034 snap_to_internal (pos, RoundUpAlways, false);
7035 _session->request_locate (pos);
7041 Editor::playhead_backward_to_grid ()
7047 framepos_t pos = playhead_cursor->current_frame ();
7050 snap_to_internal (pos, RoundDownAlways, false);
7051 _session->request_locate (pos);
7056 Editor::set_track_height (Height h)
7058 TrackSelection& ts (selection->tracks);
7060 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7061 (*x)->set_height_enum (h);
7066 Editor::toggle_tracks_active ()
7068 TrackSelection& ts (selection->tracks);
7070 bool target = false;
7076 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7077 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7081 target = !rtv->_route->active();
7084 rtv->_route->set_active (target, this);
7090 Editor::remove_tracks ()
7092 /* this will delete GUI objects that may be the subject of an event
7093 handler in which this method is called. Defer actual deletion to the
7094 next idle callback, when all event handling is finished.
7096 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7100 Editor::idle_remove_tracks ()
7102 Session::StateProtector sp (_session);
7104 return false; /* do not call again */
7108 Editor::_remove_tracks ()
7110 TrackSelection& ts (selection->tracks);
7116 vector<string> choices;
7120 const char* trackstr;
7122 vector<boost::shared_ptr<Route> > routes;
7123 bool special_bus = false;
7125 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7126 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7130 if (rtv->is_track()) {
7135 routes.push_back (rtv->_route);
7137 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7142 if (special_bus && !Config->get_allow_special_bus_removal()) {
7143 MessageDialog msg (_("That would be bad news ...."),
7147 msg.set_secondary_text (string_compose (_(
7148 "Removing the master or monitor bus is such a bad idea\n\
7149 that %1 is not going to allow it.\n\
7151 If you really want to do this sort of thing\n\
7152 edit your ardour.rc file to set the\n\
7153 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7160 if (ntracks + nbusses == 0) {
7164 trackstr = P_("track", "tracks", ntracks);
7165 busstr = P_("bus", "busses", nbusses);
7169 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7170 "(You may also lose the playlists associated with the %2)\n\n"
7171 "This action cannot be undone, and the session file will be overwritten!"),
7172 ntracks, trackstr, nbusses, busstr);
7174 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7175 "(You may also lose the playlists associated with the %2)\n\n"
7176 "This action cannot be undone, and the session file will be overwritten!"),
7179 } else if (nbusses) {
7180 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7181 "This action cannot be undone, and the session file will be overwritten"),
7185 choices.push_back (_("No, do nothing."));
7186 if (ntracks + nbusses > 1) {
7187 choices.push_back (_("Yes, remove them."));
7189 choices.push_back (_("Yes, remove it."));
7194 title = string_compose (_("Remove %1"), trackstr);
7196 title = string_compose (_("Remove %1"), busstr);
7199 Choice prompter (title, prompt, choices);
7201 if (prompter.run () != 1) {
7206 DisplaySuspender ds;
7207 boost::shared_ptr<RouteList> rl (new RouteList);
7208 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7211 _session->remove_routes (rl);
7213 /* TrackSelection and RouteList leave scope,
7214 * destructors are called,
7215 * diskstream drops references, save_state is called (again for every track)
7220 Editor::do_insert_time ()
7222 if (selection->tracks.empty()) {
7226 InsertRemoveTimeDialog d (*this);
7227 int response = d.run ();
7229 if (response != RESPONSE_OK) {
7233 if (d.distance() == 0) {
7238 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7240 d.intersected_region_action (),
7244 d.move_glued_markers(),
7245 d.move_locked_markers(),
7251 Editor::insert_time (
7252 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7253 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7257 if (Config->get_edit_mode() == Lock) {
7260 bool in_command = false;
7262 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7264 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7268 /* don't operate on any playlist more than once, which could
7269 * happen if "all playlists" is enabled, but there is more
7270 * than 1 track using playlists "from" a given track.
7273 set<boost::shared_ptr<Playlist> > pl;
7275 if (all_playlists) {
7276 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7277 if (rtav && rtav->track ()) {
7278 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7279 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7284 if ((*x)->playlist ()) {
7285 pl.insert ((*x)->playlist ());
7289 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7291 (*i)->clear_changes ();
7292 (*i)->clear_owned_changes ();
7294 if (opt == SplitIntersected) {
7298 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7301 begin_reversible_command (_("insert time"));
7304 vector<Command*> cmds;
7306 _session->add_commands (cmds);
7308 _session->add_command (new StatefulDiffCommand (*i));
7312 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7315 begin_reversible_command (_("insert time"));
7318 rtav->route ()->shift (pos, frames);
7325 XMLNode& before (_session->locations()->get_state());
7326 Locations::LocationList copy (_session->locations()->list());
7328 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7330 Locations::LocationList::const_iterator tmp;
7332 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7333 bool const was_locked = (*i)->locked ();
7334 if (locked_markers_too) {
7338 if ((*i)->start() >= pos) {
7339 // move end first, in case we're moving by more than the length of the range
7340 if (!(*i)->is_mark()) {
7341 (*i)->set_end ((*i)->end() + frames);
7343 (*i)->set_start ((*i)->start() + frames);
7355 begin_reversible_command (_("insert time"));
7358 XMLNode& after (_session->locations()->get_state());
7359 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7365 begin_reversible_command (_("insert time"));
7368 XMLNode& before (_session->tempo_map().get_state());
7369 _session->tempo_map().insert_time (pos, frames);
7370 XMLNode& after (_session->tempo_map().get_state());
7371 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7375 commit_reversible_command ();
7380 Editor::do_remove_time ()
7382 if (selection->tracks.empty()) {
7386 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7387 InsertRemoveTimeDialog d (*this, true);
7389 int response = d.run ();
7391 if (response != RESPONSE_OK) {
7395 framecnt_t distance = d.distance();
7397 if (distance == 0) {
7407 d.move_glued_markers(),
7408 d.move_locked_markers(),
7414 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7415 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7417 if (Config->get_edit_mode() == Lock) {
7418 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7421 bool in_command = false;
7423 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7425 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7429 XMLNode &before = pl->get_state();
7431 std::list<AudioRange> rl;
7432 AudioRange ar(pos, pos+frames, 0);
7435 pl->shift (pos, -frames, true, ignore_music_glue);
7438 begin_reversible_command (_("remove time"));
7441 XMLNode &after = pl->get_state();
7443 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7447 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7450 begin_reversible_command (_("remove time"));
7453 rtav->route ()->shift (pos, -frames);
7457 std::list<Location*> loc_kill_list;
7462 XMLNode& before (_session->locations()->get_state());
7463 Locations::LocationList copy (_session->locations()->list());
7465 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7466 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7468 bool const was_locked = (*i)->locked ();
7469 if (locked_markers_too) {
7473 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7474 if ((*i)->end() >= pos
7475 && (*i)->end() < pos+frames
7476 && (*i)->start() >= pos
7477 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7479 loc_kill_list.push_back(*i);
7480 } else { // only start or end is included, try to do the right thing
7481 // move start before moving end, to avoid trying to move the end to before the start
7482 // if we're removing more time than the length of the range
7483 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7484 // start is within cut
7485 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7487 } else if ((*i)->start() >= pos+frames) {
7488 // start (and thus entire range) lies beyond end of cut
7489 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7492 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7493 // end is inside cut
7494 (*i)->set_end (pos); // bring the end to the cut
7496 } else if ((*i)->end() >= pos+frames) {
7497 // end is beyond end of cut
7498 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7503 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7504 loc_kill_list.push_back(*i);
7506 } else if ((*i)->start() >= pos) {
7507 (*i)->set_start ((*i)->start() -frames);
7517 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7518 _session->locations()->remove( *i );
7523 begin_reversible_command (_("remove time"));
7526 XMLNode& after (_session->locations()->get_state());
7527 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7532 XMLNode& before (_session->tempo_map().get_state());
7534 if (_session->tempo_map().remove_time (pos, frames) ) {
7536 begin_reversible_command (_("remove time"));
7539 XMLNode& after (_session->tempo_map().get_state());
7540 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7545 commit_reversible_command ();
7550 Editor::fit_selection ()
7552 if (!selection->tracks.empty()) {
7553 fit_tracks (selection->tracks);
7557 /* no selected tracks - use tracks with selected regions */
7559 if (!selection->regions.empty()) {
7560 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7561 tvl.push_back (&(*r)->get_time_axis_view ());
7567 } else if (internal_editing()) {
7568 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7571 if (entered_track) {
7572 tvl.push_back (entered_track);
7581 Editor::fit_tracks (TrackViewList & tracks)
7583 if (tracks.empty()) {
7587 uint32_t child_heights = 0;
7588 int visible_tracks = 0;
7590 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7592 if (!(*t)->marked_for_display()) {
7596 child_heights += (*t)->effective_height() - (*t)->current_height();
7600 /* compute the per-track height from:
7602 total canvas visible height -
7603 height that will be taken by visible children of selected
7604 tracks - height of the ruler/hscroll area
7606 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7607 double first_y_pos = DBL_MAX;
7609 if (h < TimeAxisView::preset_height (HeightSmall)) {
7610 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7611 /* too small to be displayed */
7615 undo_visual_stack.push_back (current_visual_state (true));
7616 PBD::Unwinder<bool> nsv (no_save_visual, true);
7618 /* build a list of all tracks, including children */
7621 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7623 TimeAxisView::Children c = (*i)->get_child_list ();
7624 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7625 all.push_back (j->get());
7630 // find selection range.
7631 // if someone knows how to user TrackViewList::iterator for this
7633 int selected_top = -1;
7634 int selected_bottom = -1;
7636 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7637 if ((*t)->marked_for_display ()) {
7638 if (tracks.contains(*t)) {
7639 if (selected_top == -1) {
7642 selected_bottom = i;
7648 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7649 if ((*t)->marked_for_display ()) {
7650 if (tracks.contains(*t)) {
7651 (*t)->set_height (h);
7652 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7654 if (i > selected_top && i < selected_bottom) {
7655 hide_track_in_display (*t);
7662 set the controls_layout height now, because waiting for its size
7663 request signal handler will cause the vertical adjustment setting to fail
7666 controls_layout.property_height () = _full_canvas_height;
7667 vertical_adjustment.set_value (first_y_pos);
7669 redo_visual_stack.push_back (current_visual_state (true));
7671 visible_tracks_selector.set_text (_("Sel"));
7675 Editor::save_visual_state (uint32_t n)
7677 while (visual_states.size() <= n) {
7678 visual_states.push_back (0);
7681 if (visual_states[n] != 0) {
7682 delete visual_states[n];
7685 visual_states[n] = current_visual_state (true);
7690 Editor::goto_visual_state (uint32_t n)
7692 if (visual_states.size() <= n) {
7696 if (visual_states[n] == 0) {
7700 use_visual_state (*visual_states[n]);
7704 Editor::start_visual_state_op (uint32_t n)
7706 save_visual_state (n);
7708 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7710 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7711 pup->set_text (buf);
7716 Editor::cancel_visual_state_op (uint32_t n)
7718 goto_visual_state (n);
7722 Editor::toggle_region_mute ()
7724 if (_ignore_region_action) {
7728 RegionSelection rs = get_regions_from_selection_and_entered ();
7734 if (rs.size() > 1) {
7735 begin_reversible_command (_("mute regions"));
7737 begin_reversible_command (_("mute region"));
7740 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7742 (*i)->region()->playlist()->clear_changes ();
7743 (*i)->region()->set_muted (!(*i)->region()->muted ());
7744 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7748 commit_reversible_command ();
7752 Editor::combine_regions ()
7754 /* foreach track with selected regions, take all selected regions
7755 and join them into a new region containing the subregions (as a
7759 typedef set<RouteTimeAxisView*> RTVS;
7762 if (selection->regions.empty()) {
7766 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7767 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7770 tracks.insert (rtv);
7774 begin_reversible_command (_("combine regions"));
7776 vector<RegionView*> new_selection;
7778 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7781 if ((rv = (*i)->combine_regions ()) != 0) {
7782 new_selection.push_back (rv);
7786 selection->clear_regions ();
7787 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7788 selection->add (*i);
7791 commit_reversible_command ();
7795 Editor::uncombine_regions ()
7797 typedef set<RouteTimeAxisView*> RTVS;
7800 if (selection->regions.empty()) {
7804 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7805 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7808 tracks.insert (rtv);
7812 begin_reversible_command (_("uncombine regions"));
7814 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7815 (*i)->uncombine_regions ();
7818 commit_reversible_command ();
7822 Editor::toggle_midi_input_active (bool flip_others)
7825 boost::shared_ptr<RouteList> rl (new RouteList);
7827 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7828 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7834 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7837 rl->push_back (rtav->route());
7838 onoff = !mt->input_active();
7842 _session->set_exclusive_input_active (rl, onoff, flip_others);
7849 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7851 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7852 lock_dialog->get_vbox()->pack_start (*padlock);
7854 ArdourButton* b = manage (new ArdourButton);
7855 b->set_name ("lock button");
7856 b->set_text (_("Click to unlock"));
7857 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7858 lock_dialog->get_vbox()->pack_start (*b);
7860 lock_dialog->get_vbox()->show_all ();
7861 lock_dialog->set_size_request (200, 200);
7864 delete _main_menu_disabler;
7865 _main_menu_disabler = new MainMenuDisabler;
7867 lock_dialog->present ();
7873 lock_dialog->hide ();
7875 delete _main_menu_disabler;
7876 _main_menu_disabler = 0;
7878 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7879 start_lock_event_timing ();
7884 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7886 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7890 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7892 Timers::TimerSuspender t;
7893 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7894 Gtkmm2ext::UI::instance()->flush_pending ();
7898 Editor::bring_all_sources_into_session ()
7905 ArdourDialog w (_("Moving embedded files into session folder"));
7906 w.get_vbox()->pack_start (msg);
7909 /* flush all pending GUI events because we're about to start copying
7913 Timers::TimerSuspender t;
7914 Gtkmm2ext::UI::instance()->flush_pending ();
7918 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));