2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
60 #include "ardour/transpose.h"
62 #include "canvas/canvas.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_remove_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
100 #include "transform_dialog.h"
101 #include "ui_config.h"
106 using namespace ARDOUR;
109 using namespace Gtkmm2ext;
110 using namespace Editing;
111 using Gtkmm2ext::Keyboard;
113 /***********************************************************************
115 ***********************************************************************/
118 Editor::undo (uint32_t n)
120 if (_drags->active ()) {
126 if (_session->undo_depth() == 0) {
127 undo_action->set_sensitive(false);
129 redo_action->set_sensitive(true);
130 begin_selection_op_history ();
135 Editor::redo (uint32_t n)
137 if (_drags->active ()) {
143 if (_session->redo_depth() == 0) {
144 redo_action->set_sensitive(false);
146 undo_action->set_sensitive(true);
147 begin_selection_op_history ();
152 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
156 RegionSelection pre_selected_regions = selection->regions;
157 bool working_on_selection = !pre_selected_regions.empty();
159 list<boost::shared_ptr<Playlist> > used_playlists;
160 list<RouteTimeAxisView*> used_trackviews;
162 if (regions.empty()) {
166 begin_reversible_command (_("split"));
168 // if splitting a single region, and snap-to is using
169 // region boundaries, don't pay attention to them
171 if (regions.size() == 1) {
172 switch (_snap_type) {
173 case SnapToRegionStart:
174 case SnapToRegionSync:
175 case SnapToRegionEnd:
184 EditorFreeze(); /* Emit Signal */
187 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
189 RegionSelection::iterator tmp;
191 /* XXX this test needs to be more complicated, to make sure we really
192 have something to split.
195 if (!(*a)->region()->covers (where)) {
203 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
211 /* we haven't seen this playlist before */
213 /* remember used playlists so we can thaw them later */
214 used_playlists.push_back(pl);
216 TimeAxisView& tv = (*a)->get_time_axis_view();
217 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
219 used_trackviews.push_back (rtv);
226 pl->clear_changes ();
227 pl->split_region ((*a)->region(), where);
228 _session->add_command (new StatefulDiffCommand (pl));
234 latest_regionviews.clear ();
236 vector<sigc::connection> region_added_connections;
238 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
239 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
242 while (used_playlists.size() > 0) {
243 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
245 used_playlists.pop_front();
248 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
253 EditorThaw(); /* Emit Signal */
256 if (working_on_selection) {
257 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
259 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
260 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
261 /* There are three classes of regions that we might want selected after
262 splitting selected regions:
263 - regions selected before the split operation, and unaffected by it
264 - newly-created regions before the split
265 - newly-created regions after the split
268 if (rsas & Existing) {
269 // region selections that existed before the split.
270 selection->add ( pre_selected_regions );
273 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
274 if ((*ri)->region()->position() < where) {
275 // new regions created before the split
276 if (rsas & NewlyCreatedLeft) {
277 selection->add (*ri);
280 // new regions created after the split
281 if (rsas & NewlyCreatedRight) {
282 selection->add (*ri);
286 _ignore_follow_edits = false;
288 _ignore_follow_edits = true;
289 if( working_on_selection ) {
290 selection->add (latest_regionviews); //these are the new regions created after the split
292 _ignore_follow_edits = false;
295 commit_reversible_command ();
298 /** Move one extreme of the current range selection. If more than one range is selected,
299 * the start of the earliest range or the end of the latest range is moved.
301 * @param move_end true to move the end of the current range selection, false to move
303 * @param next true to move the extreme to the next region boundary, false to move to
307 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
309 if (selection->time.start() == selection->time.end_frame()) {
313 framepos_t start = selection->time.start ();
314 framepos_t end = selection->time.end_frame ();
316 /* the position of the thing we may move */
317 framepos_t pos = move_end ? end : start;
318 int dir = next ? 1 : -1;
320 /* so we don't find the current region again */
321 if (dir > 0 || pos > 0) {
325 framepos_t const target = get_region_boundary (pos, dir, true, false);
340 begin_reversible_selection_op (_("alter selection"));
341 selection->set_preserving_all_ranges (start, end);
342 commit_reversible_selection_op ();
346 Editor::nudge_forward_release (GdkEventButton* ev)
348 if (ev->state & Keyboard::PrimaryModifier) {
349 nudge_forward (false, true);
351 nudge_forward (false, false);
357 Editor::nudge_backward_release (GdkEventButton* ev)
359 if (ev->state & Keyboard::PrimaryModifier) {
360 nudge_backward (false, true);
362 nudge_backward (false, false);
369 Editor::nudge_forward (bool next, bool force_playhead)
372 framepos_t next_distance;
378 RegionSelection rs = get_regions_from_selection_and_entered ();
380 if (!force_playhead && !rs.empty()) {
382 begin_reversible_command (_("nudge regions forward"));
384 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
385 boost::shared_ptr<Region> r ((*i)->region());
387 distance = get_nudge_distance (r->position(), next_distance);
390 distance = next_distance;
394 r->set_position (r->position() + distance);
395 _session->add_command (new StatefulDiffCommand (r));
398 commit_reversible_command ();
401 } else if (!force_playhead && !selection->markers.empty()) {
404 bool in_command = false;
406 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
408 Location* loc = find_location_from_marker ((*i), is_start);
412 XMLNode& before (loc->get_state());
415 distance = get_nudge_distance (loc->start(), next_distance);
417 distance = next_distance;
419 if (max_framepos - distance > loc->start() + loc->length()) {
420 loc->set_start (loc->start() + distance);
422 loc->set_start (max_framepos - loc->length());
425 distance = get_nudge_distance (loc->end(), next_distance);
427 distance = next_distance;
429 if (max_framepos - distance > loc->end()) {
430 loc->set_end (loc->end() + distance);
432 loc->set_end (max_framepos);
436 begin_reversible_command (_("nudge location forward"));
439 XMLNode& after (loc->get_state());
440 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
445 commit_reversible_command ();
448 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
449 _session->request_locate (playhead_cursor->current_frame () + distance);
454 Editor::nudge_backward (bool next, bool force_playhead)
457 framepos_t next_distance;
463 RegionSelection rs = get_regions_from_selection_and_entered ();
465 if (!force_playhead && !rs.empty()) {
467 begin_reversible_command (_("nudge regions backward"));
469 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
470 boost::shared_ptr<Region> r ((*i)->region());
472 distance = get_nudge_distance (r->position(), next_distance);
475 distance = next_distance;
480 if (r->position() > distance) {
481 r->set_position (r->position() - distance);
485 _session->add_command (new StatefulDiffCommand (r));
488 commit_reversible_command ();
490 } else if (!force_playhead && !selection->markers.empty()) {
493 bool in_command = false;
495 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
497 Location* loc = find_location_from_marker ((*i), is_start);
501 XMLNode& before (loc->get_state());
504 distance = get_nudge_distance (loc->start(), next_distance);
506 distance = next_distance;
508 if (distance < loc->start()) {
509 loc->set_start (loc->start() - distance);
514 distance = get_nudge_distance (loc->end(), next_distance);
517 distance = next_distance;
520 if (distance < loc->end() - loc->length()) {
521 loc->set_end (loc->end() - distance);
523 loc->set_end (loc->length());
527 begin_reversible_command (_("nudge location forward"));
530 XMLNode& after (loc->get_state());
531 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
535 commit_reversible_command ();
540 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
542 if (playhead_cursor->current_frame () > distance) {
543 _session->request_locate (playhead_cursor->current_frame () - distance);
545 _session->goto_start();
551 Editor::nudge_forward_capture_offset ()
553 RegionSelection rs = get_regions_from_selection_and_entered ();
555 if (!_session || rs.empty()) {
559 begin_reversible_command (_("nudge forward"));
561 framepos_t const distance = _session->worst_output_latency();
563 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
564 boost::shared_ptr<Region> r ((*i)->region());
567 r->set_position (r->position() + distance);
568 _session->add_command(new StatefulDiffCommand (r));
571 commit_reversible_command ();
575 Editor::nudge_backward_capture_offset ()
577 RegionSelection rs = get_regions_from_selection_and_entered ();
579 if (!_session || rs.empty()) {
583 begin_reversible_command (_("nudge backward"));
585 framepos_t const distance = _session->worst_output_latency();
587 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
588 boost::shared_ptr<Region> r ((*i)->region());
592 if (r->position() > distance) {
593 r->set_position (r->position() - distance);
597 _session->add_command(new StatefulDiffCommand (r));
600 commit_reversible_command ();
603 struct RegionSelectionPositionSorter {
604 bool operator() (RegionView* a, RegionView* b) {
605 return a->region()->position() < b->region()->position();
610 Editor::sequence_regions ()
613 framepos_t r_end_prev;
621 RegionSelection rs = get_regions_from_selection_and_entered ();
622 rs.sort(RegionSelectionPositionSorter());
626 bool in_command = false;
628 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
629 boost::shared_ptr<Region> r ((*i)->region());
637 if(r->position_locked())
644 r->set_position(r_end_prev);
648 begin_reversible_command (_("sequence regions"));
651 _session->add_command (new StatefulDiffCommand (r));
653 r_end=r->position() + r->length();
659 commit_reversible_command ();
668 Editor::move_to_start ()
670 _session->goto_start ();
674 Editor::move_to_end ()
677 _session->request_locate (_session->current_end_frame());
681 Editor::build_region_boundary_cache ()
684 vector<RegionPoint> interesting_points;
685 boost::shared_ptr<Region> r;
686 TrackViewList tracks;
689 region_boundary_cache.clear ();
695 switch (_snap_type) {
696 case SnapToRegionStart:
697 interesting_points.push_back (Start);
699 case SnapToRegionEnd:
700 interesting_points.push_back (End);
702 case SnapToRegionSync:
703 interesting_points.push_back (SyncPoint);
705 case SnapToRegionBoundary:
706 interesting_points.push_back (Start);
707 interesting_points.push_back (End);
710 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
711 abort(); /*NOTREACHED*/
715 TimeAxisView *ontrack = 0;
718 if (!selection->tracks.empty()) {
719 tlist = selection->tracks.filter_to_unique_playlists ();
721 tlist = track_views.filter_to_unique_playlists ();
724 while (pos < _session->current_end_frame() && !at_end) {
727 framepos_t lpos = max_framepos;
729 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
731 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
732 if (*p == interesting_points.back()) {
735 /* move to next point type */
741 rpos = r->first_frame();
745 rpos = r->last_frame();
749 rpos = r->sync_position ();
757 RouteTimeAxisView *rtav;
759 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
760 if (rtav->track() != 0) {
761 speed = rtav->track()->speed();
765 rpos = track_frame_to_session_frame (rpos, speed);
771 /* prevent duplicates, but we don't use set<> because we want to be able
775 vector<framepos_t>::iterator ri;
777 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
783 if (ri == region_boundary_cache.end()) {
784 region_boundary_cache.push_back (rpos);
791 /* finally sort to be sure that the order is correct */
793 sort (region_boundary_cache.begin(), region_boundary_cache.end());
796 boost::shared_ptr<Region>
797 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
799 TrackViewList::iterator i;
800 framepos_t closest = max_framepos;
801 boost::shared_ptr<Region> ret;
805 framepos_t track_frame;
806 RouteTimeAxisView *rtav;
808 for (i = tracks.begin(); i != tracks.end(); ++i) {
811 boost::shared_ptr<Region> r;
814 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
815 if (rtav->track()!=0)
816 track_speed = rtav->track()->speed();
819 track_frame = session_frame_to_track_frame(frame, track_speed);
821 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
827 rpos = r->first_frame ();
831 rpos = r->last_frame ();
835 rpos = r->sync_position ();
839 // rpos is a "track frame", converting it to "_session frame"
840 rpos = track_frame_to_session_frame(rpos, track_speed);
843 distance = rpos - frame;
845 distance = frame - rpos;
848 if (distance < closest) {
860 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
862 framecnt_t distance = max_framepos;
863 framepos_t current_nearest = -1;
865 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
866 framepos_t contender;
869 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
875 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
879 d = ::llabs (pos - contender);
882 current_nearest = contender;
887 return current_nearest;
891 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
896 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
898 if (!selection->tracks.empty()) {
900 target = find_next_region_boundary (pos, dir, selection->tracks);
904 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
905 get_onscreen_tracks (tvl);
906 target = find_next_region_boundary (pos, dir, tvl);
908 target = find_next_region_boundary (pos, dir, track_views);
914 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
915 get_onscreen_tracks (tvl);
916 target = find_next_region_boundary (pos, dir, tvl);
918 target = find_next_region_boundary (pos, dir, track_views);
926 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
928 framepos_t pos = playhead_cursor->current_frame ();
935 // so we don't find the current region again..
936 if (dir > 0 || pos > 0) {
940 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
944 _session->request_locate (target);
948 Editor::cursor_to_next_region_boundary (bool with_selection)
950 cursor_to_region_boundary (with_selection, 1);
954 Editor::cursor_to_previous_region_boundary (bool with_selection)
956 cursor_to_region_boundary (with_selection, -1);
960 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
962 boost::shared_ptr<Region> r;
963 framepos_t pos = cursor->current_frame ();
969 TimeAxisView *ontrack = 0;
971 // so we don't find the current region again..
975 if (!selection->tracks.empty()) {
977 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
979 } else if (clicked_axisview) {
982 t.push_back (clicked_axisview);
984 r = find_next_region (pos, point, dir, t, &ontrack);
988 r = find_next_region (pos, point, dir, track_views, &ontrack);
997 pos = r->first_frame ();
1001 pos = r->last_frame ();
1005 pos = r->sync_position ();
1010 RouteTimeAxisView *rtav;
1012 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1013 if (rtav->track() != 0) {
1014 speed = rtav->track()->speed();
1018 pos = track_frame_to_session_frame(pos, speed);
1020 if (cursor == playhead_cursor) {
1021 _session->request_locate (pos);
1023 cursor->set_position (pos);
1028 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1030 cursor_to_region_point (cursor, point, 1);
1034 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1036 cursor_to_region_point (cursor, point, -1);
1040 Editor::cursor_to_selection_start (EditorCursor *cursor)
1044 switch (mouse_mode) {
1046 if (!selection->regions.empty()) {
1047 pos = selection->regions.start();
1052 if (!selection->time.empty()) {
1053 pos = selection->time.start ();
1061 if (cursor == playhead_cursor) {
1062 _session->request_locate (pos);
1064 cursor->set_position (pos);
1069 Editor::cursor_to_selection_end (EditorCursor *cursor)
1073 switch (mouse_mode) {
1075 if (!selection->regions.empty()) {
1076 pos = selection->regions.end_frame();
1081 if (!selection->time.empty()) {
1082 pos = selection->time.end_frame ();
1090 if (cursor == playhead_cursor) {
1091 _session->request_locate (pos);
1093 cursor->set_position (pos);
1098 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1108 if (selection->markers.empty()) {
1112 if (!mouse_frame (mouse, ignored)) {
1116 add_location_mark (mouse);
1119 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1123 framepos_t pos = loc->start();
1125 // so we don't find the current region again..
1126 if (dir > 0 || pos > 0) {
1130 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1134 loc->move_to (target);
1138 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1140 selected_marker_to_region_boundary (with_selection, 1);
1144 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1146 selected_marker_to_region_boundary (with_selection, -1);
1150 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1152 boost::shared_ptr<Region> r;
1157 if (!_session || selection->markers.empty()) {
1161 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1165 TimeAxisView *ontrack = 0;
1169 // so we don't find the current region again..
1173 if (!selection->tracks.empty()) {
1175 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1179 r = find_next_region (pos, point, dir, track_views, &ontrack);
1188 pos = r->first_frame ();
1192 pos = r->last_frame ();
1196 pos = r->adjust_to_sync (r->first_frame());
1201 RouteTimeAxisView *rtav;
1203 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1204 if (rtav->track() != 0) {
1205 speed = rtav->track()->speed();
1209 pos = track_frame_to_session_frame(pos, speed);
1215 Editor::selected_marker_to_next_region_point (RegionPoint point)
1217 selected_marker_to_region_point (point, 1);
1221 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1223 selected_marker_to_region_point (point, -1);
1227 Editor::selected_marker_to_selection_start ()
1233 if (!_session || selection->markers.empty()) {
1237 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1241 switch (mouse_mode) {
1243 if (!selection->regions.empty()) {
1244 pos = selection->regions.start();
1249 if (!selection->time.empty()) {
1250 pos = selection->time.start ();
1262 Editor::selected_marker_to_selection_end ()
1268 if (!_session || selection->markers.empty()) {
1272 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1276 switch (mouse_mode) {
1278 if (!selection->regions.empty()) {
1279 pos = selection->regions.end_frame();
1284 if (!selection->time.empty()) {
1285 pos = selection->time.end_frame ();
1297 Editor::scroll_playhead (bool forward)
1299 framepos_t pos = playhead_cursor->current_frame ();
1300 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1303 if (pos == max_framepos) {
1307 if (pos < max_framepos - delta) {
1326 _session->request_locate (pos);
1330 Editor::cursor_align (bool playhead_to_edit)
1336 if (playhead_to_edit) {
1338 if (selection->markers.empty()) {
1342 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1345 /* move selected markers to playhead */
1347 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1350 Location* loc = find_location_from_marker (*i, ignored);
1352 if (loc->is_mark()) {
1353 loc->set_start (playhead_cursor->current_frame ());
1355 loc->set (playhead_cursor->current_frame (),
1356 playhead_cursor->current_frame () + loc->length());
1363 Editor::scroll_backward (float pages)
1365 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1366 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1369 if (leftmost_frame < cnt) {
1372 frame = leftmost_frame - cnt;
1375 reset_x_origin (frame);
1379 Editor::scroll_forward (float pages)
1381 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1382 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1385 if (max_framepos - cnt < leftmost_frame) {
1386 frame = max_framepos - cnt;
1388 frame = leftmost_frame + cnt;
1391 reset_x_origin (frame);
1395 Editor::scroll_tracks_down ()
1397 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1398 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1399 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1402 vertical_adjustment.set_value (vert_value);
1406 Editor::scroll_tracks_up ()
1408 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1412 Editor::scroll_tracks_down_line ()
1414 double vert_value = vertical_adjustment.get_value() + 60;
1416 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1417 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1420 vertical_adjustment.set_value (vert_value);
1424 Editor::scroll_tracks_up_line ()
1426 reset_y_origin (vertical_adjustment.get_value() - 60);
1430 Editor::scroll_down_one_track (bool skip_child_views)
1432 TrackViewList::reverse_iterator next = track_views.rend();
1433 const double top_of_trackviews = vertical_adjustment.get_value();
1435 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1436 if ((*t)->hidden()) {
1440 /* If this is the upper-most visible trackview, we want to display
1441 * the one above it (next)
1443 * Note that covers_y_position() is recursive and includes child views
1445 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1448 if (skip_child_views) {
1451 /* automation lane (one level, non-recursive)
1453 * - if no automation lane exists -> move to next tack
1454 * - if the first (here: bottom-most) matches -> move to next tack
1455 * - if no y-axis match is found -> the current track is at the top
1456 * -> move to last (here: top-most) automation lane
1458 TimeAxisView::Children kids = (*t)->get_child_list();
1459 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1461 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1462 if ((*ci)->hidden()) {
1466 std::pair<TimeAxisView*,double> dev;
1467 dev = (*ci)->covers_y_position (top_of_trackviews);
1469 /* some automation lane is currently at the top */
1470 if (ci == kids.rbegin()) {
1471 /* first (bottom-most) autmation lane is at the top.
1472 * -> move to next track
1481 if (nkid != kids.rend()) {
1482 ensure_time_axis_view_is_visible (**nkid, true);
1490 /* move to the track below the first one that covers the */
1492 if (next != track_views.rend()) {
1493 ensure_time_axis_view_is_visible (**next, true);
1501 Editor::scroll_up_one_track (bool skip_child_views)
1503 TrackViewList::iterator prev = track_views.end();
1504 double top_of_trackviews = vertical_adjustment.get_value ();
1506 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1508 if ((*t)->hidden()) {
1512 /* find the trackview at the top of the trackview group
1514 * Note that covers_y_position() is recursive and includes child views
1516 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1519 if (skip_child_views) {
1522 /* automation lane (one level, non-recursive)
1524 * - if no automation lane exists -> move to prev tack
1525 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1526 * (actually last automation lane of previous track, see below)
1527 * - if first (top-most) lane is at the top -> move to this track
1528 * - else move up one lane
1530 TimeAxisView::Children kids = (*t)->get_child_list();
1531 TimeAxisView::Children::iterator pkid = kids.end();
1533 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1534 if ((*ci)->hidden()) {
1538 std::pair<TimeAxisView*,double> dev;
1539 dev = (*ci)->covers_y_position (top_of_trackviews);
1541 /* some automation lane is currently at the top */
1542 if (ci == kids.begin()) {
1543 /* first (top-most) autmation lane is at the top.
1544 * jump directly to this track's top
1546 ensure_time_axis_view_is_visible (**t, true);
1549 else if (pkid != kids.end()) {
1550 /* some other automation lane is at the top.
1551 * move up to prev automation lane.
1553 ensure_time_axis_view_is_visible (**pkid, true);
1556 assert(0); // not reached
1567 if (prev != track_views.end()) {
1568 // move to bottom-most automation-lane of the previous track
1569 TimeAxisView::Children kids = (*prev)->get_child_list();
1570 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1571 if (!skip_child_views) {
1572 // find the last visible lane
1573 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1574 if (!(*ci)->hidden()) {
1580 if (pkid != kids.rend()) {
1581 ensure_time_axis_view_is_visible (**pkid, true);
1583 ensure_time_axis_view_is_visible (**prev, true);
1594 Editor::tav_zoom_step (bool coarser)
1596 DisplaySuspender ds;
1600 if (selection->tracks.empty()) {
1603 ts = &selection->tracks;
1606 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1607 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1608 tv->step_height (coarser);
1613 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1615 DisplaySuspender ds;
1619 if (selection->tracks.empty() || force_all) {
1622 ts = &selection->tracks;
1625 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1626 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1627 uint32_t h = tv->current_height ();
1632 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1637 tv->set_height (h + 5);
1644 Editor::temporal_zoom_step (bool coarser)
1646 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1648 framecnt_t nspp = samples_per_pixel;
1656 temporal_zoom (nspp);
1660 Editor::temporal_zoom (framecnt_t fpp)
1666 framepos_t current_page = current_page_samples();
1667 framepos_t current_leftmost = leftmost_frame;
1668 framepos_t current_rightmost;
1669 framepos_t current_center;
1670 framepos_t new_page_size;
1671 framepos_t half_page_size;
1672 framepos_t leftmost_after_zoom = 0;
1674 bool in_track_canvas;
1678 if (fpp == samples_per_pixel) {
1682 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1683 // segfaults for lack of memory. If somebody decides this is not high enough I
1684 // believe it can be raisen to higher values but some limit must be in place.
1686 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1687 // all of which is used for the editor track displays. The whole day
1688 // would be 4147200000 samples, so 2592000 samples per pixel.
1690 nfpp = min (fpp, (framecnt_t) 2592000);
1691 nfpp = max ((framecnt_t) 1, nfpp);
1693 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1694 half_page_size = new_page_size / 2;
1696 switch (zoom_focus) {
1698 leftmost_after_zoom = current_leftmost;
1701 case ZoomFocusRight:
1702 current_rightmost = leftmost_frame + current_page;
1703 if (current_rightmost < new_page_size) {
1704 leftmost_after_zoom = 0;
1706 leftmost_after_zoom = current_rightmost - new_page_size;
1710 case ZoomFocusCenter:
1711 current_center = current_leftmost + (current_page/2);
1712 if (current_center < half_page_size) {
1713 leftmost_after_zoom = 0;
1715 leftmost_after_zoom = current_center - half_page_size;
1719 case ZoomFocusPlayhead:
1720 /* centre playhead */
1721 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1724 leftmost_after_zoom = 0;
1725 } else if (l > max_framepos) {
1726 leftmost_after_zoom = max_framepos - new_page_size;
1728 leftmost_after_zoom = (framepos_t) l;
1732 case ZoomFocusMouse:
1733 /* try to keep the mouse over the same point in the display */
1735 if (!mouse_frame (where, in_track_canvas)) {
1736 /* use playhead instead */
1737 where = playhead_cursor->current_frame ();
1739 if (where < half_page_size) {
1740 leftmost_after_zoom = 0;
1742 leftmost_after_zoom = where - half_page_size;
1747 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1750 leftmost_after_zoom = 0;
1751 } else if (l > max_framepos) {
1752 leftmost_after_zoom = max_framepos - new_page_size;
1754 leftmost_after_zoom = (framepos_t) l;
1761 /* try to keep the edit point in the same place */
1762 where = get_preferred_edit_position ();
1766 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1769 leftmost_after_zoom = 0;
1770 } else if (l > max_framepos) {
1771 leftmost_after_zoom = max_framepos - new_page_size;
1773 leftmost_after_zoom = (framepos_t) l;
1777 /* edit point not defined */
1784 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1786 reposition_and_zoom (leftmost_after_zoom, nfpp);
1790 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1792 /* this func helps make sure we leave a little space
1793 at each end of the editor so that the zoom doesn't fit the region
1794 precisely to the screen.
1797 GdkScreen* screen = gdk_screen_get_default ();
1798 const gint pixwidth = gdk_screen_get_width (screen);
1799 const gint mmwidth = gdk_screen_get_width_mm (screen);
1800 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1801 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1803 const framepos_t range = end - start;
1804 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1805 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1807 if (start > extra_samples) {
1808 start -= extra_samples;
1813 if (max_framepos - extra_samples > end) {
1814 end += extra_samples;
1821 Editor::temporal_zoom_region (bool both_axes)
1823 framepos_t start = max_framepos;
1825 set<TimeAxisView*> tracks;
1827 if ( !get_selection_extents(start, end) )
1830 calc_extra_zoom_edges (start, end);
1832 /* if we're zooming on both axes we need to save track heights etc.
1835 undo_visual_stack.push_back (current_visual_state (both_axes));
1837 PBD::Unwinder<bool> nsv (no_save_visual, true);
1839 temporal_zoom_by_frame (start, end);
1842 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1844 /* set visible track heights appropriately */
1846 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1847 (*t)->set_height (per_track_height);
1850 /* hide irrelevant tracks */
1852 DisplaySuspender ds;
1854 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1855 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1856 hide_track_in_display (*i);
1860 vertical_adjustment.set_value (0.0);
1863 redo_visual_stack.push_back (current_visual_state (both_axes));
1868 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1870 start = max_framepos;
1874 //ToDo: if notes are selected, set extents to that selection
1876 //ToDo: if control points are selected, set extents to that selection
1878 if ( !selection->regions.empty() ) {
1879 RegionSelection rs = get_regions_from_selection_and_entered ();
1881 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1883 if ((*i)->region()->position() < start) {
1884 start = (*i)->region()->position();
1887 if ((*i)->region()->last_frame() + 1 > end) {
1888 end = (*i)->region()->last_frame() + 1;
1892 } else if (!selection->time.empty()) {
1893 start = selection->time.start();
1894 end = selection->time.end_frame();
1896 ret = false; //no selection found
1899 if ((start == 0 && end == 0) || end < start) {
1908 Editor::temporal_zoom_selection (bool both_axes)
1910 if (!selection) return;
1912 //ToDo: if notes are selected, zoom to that
1914 //ToDo: if control points are selected, zoom to that
1916 //if region(s) are selected, zoom to that
1917 if ( !selection->regions.empty() )
1918 temporal_zoom_region (both_axes);
1920 //if a range is selected, zoom to that
1921 if (!selection->time.empty()) {
1923 framepos_t start, end;
1924 if (get_selection_extents (start, end)) {
1925 calc_extra_zoom_edges(start, end);
1926 temporal_zoom_by_frame (start, end);
1936 Editor::temporal_zoom_session ()
1938 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1941 framecnt_t start = _session->current_start_frame();
1942 framecnt_t end = _session->current_end_frame();
1944 if (_session->actively_recording () ) {
1945 framepos_t cur = playhead_cursor->current_frame ();
1947 /* recording beyond the end marker; zoom out
1948 * by 5 seconds more so that if 'follow
1949 * playhead' is active we don't immediately
1952 end = cur + _session->frame_rate() * 5;
1956 if ((start == 0 && end == 0) || end < start) {
1960 calc_extra_zoom_edges(start, end);
1962 temporal_zoom_by_frame (start, end);
1967 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1969 if (!_session) return;
1971 if ((start == 0 && end == 0) || end < start) {
1975 framepos_t range = end - start;
1977 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1979 framepos_t new_page = range;
1980 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1981 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1983 if (new_leftmost > middle) {
1987 if (new_leftmost < 0) {
1991 reposition_and_zoom (new_leftmost, new_fpp);
1995 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2001 framecnt_t range_before = frame - leftmost_frame;
2005 if (samples_per_pixel <= 1) {
2008 new_spp = samples_per_pixel + (samples_per_pixel/2);
2010 range_before += range_before/2;
2012 if (samples_per_pixel >= 1) {
2013 new_spp = samples_per_pixel - (samples_per_pixel/2);
2015 /* could bail out here since we cannot zoom any finer,
2016 but leave that to the equality test below
2018 new_spp = samples_per_pixel;
2021 range_before -= range_before/2;
2024 if (new_spp == samples_per_pixel) {
2028 /* zoom focus is automatically taken as @param frame when this
2032 framepos_t new_leftmost = frame - (framepos_t)range_before;
2034 if (new_leftmost > frame) {
2038 if (new_leftmost < 0) {
2042 reposition_and_zoom (new_leftmost, new_spp);
2047 Editor::choose_new_marker_name(string &name) {
2049 if (!UIConfiguration::instance().get_name_new_markers()) {
2050 /* don't prompt user for a new name */
2054 ArdourPrompter dialog (true);
2056 dialog.set_prompt (_("New Name:"));
2058 dialog.set_title (_("New Location Marker"));
2060 dialog.set_name ("MarkNameWindow");
2061 dialog.set_size_request (250, -1);
2062 dialog.set_position (Gtk::WIN_POS_MOUSE);
2064 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2065 dialog.set_initial_text (name);
2069 switch (dialog.run ()) {
2070 case RESPONSE_ACCEPT:
2076 dialog.get_result(name);
2083 Editor::add_location_from_selection ()
2087 if (selection->time.empty()) {
2091 if (_session == 0 || clicked_axisview == 0) {
2095 framepos_t start = selection->time[clicked_selection].start;
2096 framepos_t end = selection->time[clicked_selection].end;
2098 _session->locations()->next_available_name(rangename,"selection");
2099 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2101 begin_reversible_command (_("add marker"));
2103 XMLNode &before = _session->locations()->get_state();
2104 _session->locations()->add (location, true);
2105 XMLNode &after = _session->locations()->get_state();
2106 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2108 commit_reversible_command ();
2112 Editor::add_location_mark (framepos_t where)
2116 select_new_marker = true;
2118 _session->locations()->next_available_name(markername,"mark");
2119 if (!choose_new_marker_name(markername)) {
2122 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2123 begin_reversible_command (_("add marker"));
2125 XMLNode &before = _session->locations()->get_state();
2126 _session->locations()->add (location, true);
2127 XMLNode &after = _session->locations()->get_state();
2128 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2130 commit_reversible_command ();
2134 Editor::set_session_start_from_playhead ()
2140 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2141 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2143 XMLNode &before = loc->get_state();
2145 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2147 XMLNode &after = loc->get_state();
2149 begin_reversible_command (_("Set session start"));
2151 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2153 commit_reversible_command ();
2158 Editor::set_session_end_from_playhead ()
2164 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2165 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2167 XMLNode &before = loc->get_state();
2169 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2171 XMLNode &after = loc->get_state();
2173 begin_reversible_command (_("Set session start"));
2175 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2177 commit_reversible_command ();
2182 Editor::add_location_from_playhead_cursor ()
2184 add_location_mark (_session->audible_frame());
2188 Editor::remove_location_at_playhead_cursor ()
2192 XMLNode &before = _session->locations()->get_state();
2193 bool removed = false;
2195 //find location(s) at this time
2196 Locations::LocationList locs;
2197 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2198 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2199 if ((*i)->is_mark()) {
2200 _session->locations()->remove (*i);
2207 begin_reversible_command (_("remove marker"));
2208 XMLNode &after = _session->locations()->get_state();
2209 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2210 commit_reversible_command ();
2215 /** Add a range marker around each selected region */
2217 Editor::add_locations_from_region ()
2219 RegionSelection rs = get_regions_from_selection_and_entered ();
2224 bool commit = false;
2226 XMLNode &before = _session->locations()->get_state();
2228 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2230 boost::shared_ptr<Region> region = (*i)->region ();
2232 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2234 _session->locations()->add (location, true);
2239 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2240 XMLNode &after = _session->locations()->get_state();
2241 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2242 commit_reversible_command ();
2246 /** Add a single range marker around all selected regions */
2248 Editor::add_location_from_region ()
2250 RegionSelection rs = get_regions_from_selection_and_entered ();
2256 XMLNode &before = _session->locations()->get_state();
2260 if (rs.size() > 1) {
2261 _session->locations()->next_available_name(markername, "regions");
2263 RegionView* rv = *(rs.begin());
2264 boost::shared_ptr<Region> region = rv->region();
2265 markername = region->name();
2268 if (!choose_new_marker_name(markername)) {
2272 // single range spanning all selected
2273 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2274 _session->locations()->add (location, true);
2276 begin_reversible_command (_("add marker"));
2277 XMLNode &after = _session->locations()->get_state();
2278 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2279 commit_reversible_command ();
2285 Editor::jump_forward_to_mark ()
2291 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2297 _session->request_locate (pos, _session->transport_rolling());
2301 Editor::jump_backward_to_mark ()
2307 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2313 _session->request_locate (pos, _session->transport_rolling());
2319 framepos_t const pos = _session->audible_frame ();
2322 _session->locations()->next_available_name (markername, "mark");
2324 if (!choose_new_marker_name (markername)) {
2328 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2332 Editor::clear_markers ()
2335 begin_reversible_command (_("clear markers"));
2337 XMLNode &before = _session->locations()->get_state();
2338 _session->locations()->clear_markers ();
2339 XMLNode &after = _session->locations()->get_state();
2340 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2342 commit_reversible_command ();
2347 Editor::clear_ranges ()
2350 begin_reversible_command (_("clear ranges"));
2352 XMLNode &before = _session->locations()->get_state();
2354 _session->locations()->clear_ranges ();
2356 XMLNode &after = _session->locations()->get_state();
2357 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2359 commit_reversible_command ();
2364 Editor::clear_locations ()
2366 begin_reversible_command (_("clear locations"));
2368 XMLNode &before = _session->locations()->get_state();
2369 _session->locations()->clear ();
2370 XMLNode &after = _session->locations()->get_state();
2371 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2373 commit_reversible_command ();
2377 Editor::unhide_markers ()
2379 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2380 Location *l = (*i).first;
2381 if (l->is_hidden() && l->is_mark()) {
2382 l->set_hidden(false, this);
2388 Editor::unhide_ranges ()
2390 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2391 Location *l = (*i).first;
2392 if (l->is_hidden() && l->is_range_marker()) {
2393 l->set_hidden(false, this);
2398 /* INSERT/REPLACE */
2401 Editor::insert_region_list_selection (float times)
2403 RouteTimeAxisView *tv = 0;
2404 boost::shared_ptr<Playlist> playlist;
2406 if (clicked_routeview != 0) {
2407 tv = clicked_routeview;
2408 } else if (!selection->tracks.empty()) {
2409 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2412 } else if (entered_track != 0) {
2413 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2420 if ((playlist = tv->playlist()) == 0) {
2424 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2429 begin_reversible_command (_("insert region"));
2430 playlist->clear_changes ();
2431 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2432 if (Config->get_edit_mode() == Ripple)
2433 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2435 _session->add_command(new StatefulDiffCommand (playlist));
2436 commit_reversible_command ();
2439 /* BUILT-IN EFFECTS */
2442 Editor::reverse_selection ()
2447 /* GAIN ENVELOPE EDITING */
2450 Editor::edit_envelope ()
2457 Editor::transition_to_rolling (bool fwd)
2463 if (_session->config.get_external_sync()) {
2464 switch (Config->get_sync_source()) {
2468 /* transport controlled by the master */
2473 if (_session->is_auditioning()) {
2474 _session->cancel_audition ();
2478 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2482 Editor::play_from_start ()
2484 _session->request_locate (_session->current_start_frame(), true);
2488 Editor::play_from_edit_point ()
2490 _session->request_locate (get_preferred_edit_position(), true);
2494 Editor::play_from_edit_point_and_return ()
2496 framepos_t start_frame;
2497 framepos_t return_frame;
2499 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2501 if (_session->transport_rolling()) {
2502 _session->request_locate (start_frame, false);
2506 /* don't reset the return frame if its already set */
2508 if ((return_frame = _session->requested_return_frame()) < 0) {
2509 return_frame = _session->audible_frame();
2512 if (start_frame >= 0) {
2513 _session->request_roll_at_and_return (start_frame, return_frame);
2518 Editor::play_selection ()
2520 framepos_t start, end;
2521 if (!get_selection_extents ( start, end))
2524 AudioRange ar (start, end, 0);
2525 list<AudioRange> lar;
2528 _session->request_play_range (&lar, true);
2532 Editor::get_preroll ()
2534 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2539 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2541 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2544 location -= get_preroll();
2546 //don't try to locate before the beginning of time
2550 //if follow_playhead is on, keep the playhead on the screen
2551 if ( _follow_playhead )
2552 if ( location < leftmost_frame )
2553 location = leftmost_frame;
2555 _session->request_locate( location );
2559 Editor::play_with_preroll ()
2562 framepos_t preroll = get_preroll();
2564 framepos_t start, end;
2565 if (!get_selection_extents ( start, end))
2568 if (start > preroll)
2569 start = start - preroll;
2571 end = end + preroll; //"post-roll"
2573 AudioRange ar (start, end, 0);
2574 list<AudioRange> lar;
2577 _session->request_play_range (&lar, true);
2582 Editor::play_location (Location& location)
2584 if (location.start() <= location.end()) {
2588 _session->request_bounded_roll (location.start(), location.end());
2592 Editor::loop_location (Location& location)
2594 if (location.start() <= location.end()) {
2600 if ((tll = transport_loop_location()) != 0) {
2601 tll->set (location.start(), location.end());
2603 // enable looping, reposition and start rolling
2604 _session->request_locate (tll->start(), true);
2605 _session->request_play_loop (true);
2610 Editor::do_layer_operation (LayerOperation op)
2612 if (selection->regions.empty ()) {
2616 bool const multiple = selection->regions.size() > 1;
2620 begin_reversible_command (_("raise regions"));
2622 begin_reversible_command (_("raise region"));
2628 begin_reversible_command (_("raise regions to top"));
2630 begin_reversible_command (_("raise region to top"));
2636 begin_reversible_command (_("lower regions"));
2638 begin_reversible_command (_("lower region"));
2644 begin_reversible_command (_("lower regions to bottom"));
2646 begin_reversible_command (_("lower region"));
2651 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2652 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2653 (*i)->clear_owned_changes ();
2656 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2657 boost::shared_ptr<Region> r = (*i)->region ();
2669 r->lower_to_bottom ();
2673 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2674 vector<Command*> cmds;
2676 _session->add_commands (cmds);
2679 commit_reversible_command ();
2683 Editor::raise_region ()
2685 do_layer_operation (Raise);
2689 Editor::raise_region_to_top ()
2691 do_layer_operation (RaiseToTop);
2695 Editor::lower_region ()
2697 do_layer_operation (Lower);
2701 Editor::lower_region_to_bottom ()
2703 do_layer_operation (LowerToBottom);
2706 /** Show the region editor for the selected regions */
2708 Editor::show_region_properties ()
2710 selection->foreach_regionview (&RegionView::show_region_editor);
2713 /** Show the midi list editor for the selected MIDI regions */
2715 Editor::show_midi_list_editor ()
2717 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2721 Editor::rename_region ()
2723 RegionSelection rs = get_regions_from_selection_and_entered ();
2729 ArdourDialog d (*this, _("Rename Region"), true, false);
2731 Label label (_("New name:"));
2734 hbox.set_spacing (6);
2735 hbox.pack_start (label, false, false);
2736 hbox.pack_start (entry, true, true);
2738 d.get_vbox()->set_border_width (12);
2739 d.get_vbox()->pack_start (hbox, false, false);
2741 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2742 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2744 d.set_size_request (300, -1);
2746 entry.set_text (rs.front()->region()->name());
2747 entry.select_region (0, -1);
2749 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2755 int const ret = d.run();
2759 if (ret != RESPONSE_OK) {
2763 std::string str = entry.get_text();
2764 strip_whitespace_edges (str);
2766 rs.front()->region()->set_name (str);
2767 _regions->redisplay ();
2771 /** Start an audition of the first selected region */
2773 Editor::play_edit_range ()
2775 framepos_t start, end;
2777 if (get_edit_op_range (start, end)) {
2778 _session->request_bounded_roll (start, end);
2783 Editor::play_selected_region ()
2785 framepos_t start = max_framepos;
2788 RegionSelection rs = get_regions_from_selection_and_entered ();
2794 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2795 if ((*i)->region()->position() < start) {
2796 start = (*i)->region()->position();
2798 if ((*i)->region()->last_frame() + 1 > end) {
2799 end = (*i)->region()->last_frame() + 1;
2803 _session->request_bounded_roll (start, end);
2807 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2809 _session->audition_region (region);
2813 Editor::region_from_selection ()
2815 if (clicked_axisview == 0) {
2819 if (selection->time.empty()) {
2823 framepos_t start = selection->time[clicked_selection].start;
2824 framepos_t end = selection->time[clicked_selection].end;
2826 TrackViewList tracks = get_tracks_for_range_action ();
2828 framepos_t selection_cnt = end - start + 1;
2830 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2831 boost::shared_ptr<Region> current;
2832 boost::shared_ptr<Playlist> pl;
2833 framepos_t internal_start;
2836 if ((pl = (*i)->playlist()) == 0) {
2840 if ((current = pl->top_region_at (start)) == 0) {
2844 internal_start = start - current->position();
2845 RegionFactory::region_name (new_name, current->name(), true);
2849 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2850 plist.add (ARDOUR::Properties::length, selection_cnt);
2851 plist.add (ARDOUR::Properties::name, new_name);
2852 plist.add (ARDOUR::Properties::layer, 0);
2854 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2859 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2861 if (selection->time.empty() || selection->tracks.empty()) {
2865 framepos_t start, end;
2866 if (clicked_selection) {
2867 start = selection->time[clicked_selection].start;
2868 end = selection->time[clicked_selection].end;
2870 start = selection->time.start();
2871 end = selection->time.end_frame();
2874 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2875 sort_track_selection (ts);
2877 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2878 boost::shared_ptr<Region> current;
2879 boost::shared_ptr<Playlist> playlist;
2880 framepos_t internal_start;
2883 if ((playlist = (*i)->playlist()) == 0) {
2887 if ((current = playlist->top_region_at(start)) == 0) {
2891 internal_start = start - current->position();
2892 RegionFactory::region_name (new_name, current->name(), true);
2896 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2897 plist.add (ARDOUR::Properties::length, end - start + 1);
2898 plist.add (ARDOUR::Properties::name, new_name);
2900 new_regions.push_back (RegionFactory::create (current, plist));
2905 Editor::split_multichannel_region ()
2907 RegionSelection rs = get_regions_from_selection_and_entered ();
2913 vector< boost::shared_ptr<Region> > v;
2915 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2916 (*x)->region()->separate_by_channel (*_session, v);
2921 Editor::new_region_from_selection ()
2923 region_from_selection ();
2924 cancel_selection ();
2928 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2930 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2931 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2932 case Evoral::OverlapNone:
2940 * - selected tracks, or if there are none...
2941 * - tracks containing selected regions, or if there are none...
2946 Editor::get_tracks_for_range_action () const
2950 if (selection->tracks.empty()) {
2952 /* use tracks with selected regions */
2954 RegionSelection rs = selection->regions;
2956 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2957 TimeAxisView* tv = &(*i)->get_time_axis_view();
2959 if (!t.contains (tv)) {
2965 /* no regions and no tracks: use all tracks */
2971 t = selection->tracks;
2974 return t.filter_to_unique_playlists();
2978 Editor::separate_regions_between (const TimeSelection& ts)
2980 bool in_command = false;
2981 boost::shared_ptr<Playlist> playlist;
2982 RegionSelection new_selection;
2984 TrackViewList tmptracks = get_tracks_for_range_action ();
2985 sort_track_selection (tmptracks);
2987 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2989 RouteTimeAxisView* rtv;
2991 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2993 if (rtv->is_track()) {
2995 /* no edits to destructive tracks */
2997 if (rtv->track()->destructive()) {
3001 if ((playlist = rtv->playlist()) != 0) {
3003 playlist->clear_changes ();
3005 /* XXX need to consider musical time selections here at some point */
3007 double speed = rtv->track()->speed();
3010 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3012 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3013 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3015 latest_regionviews.clear ();
3017 playlist->partition ((framepos_t)((*t).start * speed),
3018 (framepos_t)((*t).end * speed), false);
3022 if (!latest_regionviews.empty()) {
3024 rtv->view()->foreach_regionview (sigc::bind (
3025 sigc::ptr_fun (add_if_covered),
3026 &(*t), &new_selection));
3029 begin_reversible_command (_("separate"));
3033 /* pick up changes to existing regions */
3035 vector<Command*> cmds;
3036 playlist->rdiff (cmds);
3037 _session->add_commands (cmds);
3039 /* pick up changes to the playlist itself (adds/removes)
3042 _session->add_command(new StatefulDiffCommand (playlist));
3051 // selection->set (new_selection);
3053 commit_reversible_command ();
3057 struct PlaylistState {
3058 boost::shared_ptr<Playlist> playlist;
3062 /** Take tracks from get_tracks_for_range_action and cut any regions
3063 * on those tracks so that the tracks are empty over the time
3067 Editor::separate_region_from_selection ()
3069 /* preferentially use *all* ranges in the time selection if we're in range mode
3070 to allow discontiguous operation, since get_edit_op_range() currently
3071 returns a single range.
3074 if (!selection->time.empty()) {
3076 separate_regions_between (selection->time);
3083 if (get_edit_op_range (start, end)) {
3085 AudioRange ar (start, end, 1);
3089 separate_regions_between (ts);
3095 Editor::separate_region_from_punch ()
3097 Location* loc = _session->locations()->auto_punch_location();
3099 separate_regions_using_location (*loc);
3104 Editor::separate_region_from_loop ()
3106 Location* loc = _session->locations()->auto_loop_location();
3108 separate_regions_using_location (*loc);
3113 Editor::separate_regions_using_location (Location& loc)
3115 if (loc.is_mark()) {
3119 AudioRange ar (loc.start(), loc.end(), 1);
3124 separate_regions_between (ts);
3127 /** Separate regions under the selected region */
3129 Editor::separate_under_selected_regions ()
3131 vector<PlaylistState> playlists;
3135 rs = get_regions_from_selection_and_entered();
3137 if (!_session || rs.empty()) {
3141 begin_reversible_command (_("separate region under"));
3143 list<boost::shared_ptr<Region> > regions_to_remove;
3145 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3146 // we can't just remove the region(s) in this loop because
3147 // this removes them from the RegionSelection, and they thus
3148 // disappear from underneath the iterator, and the ++i above
3149 // SEGVs in a puzzling fashion.
3151 // so, first iterate over the regions to be removed from rs and
3152 // add them to the regions_to_remove list, and then
3153 // iterate over the list to actually remove them.
3155 regions_to_remove.push_back ((*i)->region());
3158 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3160 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3163 // is this check necessary?
3167 vector<PlaylistState>::iterator i;
3169 //only take state if this is a new playlist.
3170 for (i = playlists.begin(); i != playlists.end(); ++i) {
3171 if ((*i).playlist == playlist) {
3176 if (i == playlists.end()) {
3178 PlaylistState before;
3179 before.playlist = playlist;
3180 before.before = &playlist->get_state();
3182 playlist->freeze ();
3183 playlists.push_back(before);
3186 //Partition on the region bounds
3187 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3189 //Re-add region that was just removed due to the partition operation
3190 playlist->add_region( (*rl), (*rl)->first_frame() );
3193 vector<PlaylistState>::iterator pl;
3195 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3196 (*pl).playlist->thaw ();
3197 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3200 commit_reversible_command ();
3204 Editor::crop_region_to_selection ()
3206 if (!selection->time.empty()) {
3208 crop_region_to (selection->time.start(), selection->time.end_frame());
3215 if (get_edit_op_range (start, end)) {
3216 crop_region_to (start, end);
3223 Editor::crop_region_to (framepos_t start, framepos_t end)
3225 vector<boost::shared_ptr<Playlist> > playlists;
3226 boost::shared_ptr<Playlist> playlist;
3229 if (selection->tracks.empty()) {
3230 ts = track_views.filter_to_unique_playlists();
3232 ts = selection->tracks.filter_to_unique_playlists ();
3235 sort_track_selection (ts);
3237 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3239 RouteTimeAxisView* rtv;
3241 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3243 boost::shared_ptr<Track> t = rtv->track();
3245 if (t != 0 && ! t->destructive()) {
3247 if ((playlist = rtv->playlist()) != 0) {
3248 playlists.push_back (playlist);
3254 if (playlists.empty()) {
3258 framepos_t the_start;
3261 bool in_command = false;
3263 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3265 boost::shared_ptr<Region> region;
3269 if ((region = (*i)->top_region_at(the_start)) == 0) {
3273 /* now adjust lengths to that we do the right thing
3274 if the selection extends beyond the region
3277 the_start = max (the_start, (framepos_t) region->position());
3278 if (max_framepos - the_start < region->length()) {
3279 the_end = the_start + region->length() - 1;
3281 the_end = max_framepos;
3283 the_end = min (end, the_end);
3284 cnt = the_end - the_start + 1;
3287 begin_reversible_command (_("trim to selection"));
3290 region->clear_changes ();
3291 region->trim_to (the_start, cnt);
3292 _session->add_command (new StatefulDiffCommand (region));
3296 commit_reversible_command ();
3301 Editor::region_fill_track ()
3303 RegionSelection rs = get_regions_from_selection_and_entered ();
3305 if (!_session || rs.empty()) {
3309 framepos_t const end = _session->current_end_frame ();
3310 RegionSelection foo;
3311 bool in_command = false;
3313 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3315 boost::shared_ptr<Region> region ((*i)->region());
3317 boost::shared_ptr<Playlist> pl = region->playlist();
3319 if (end <= region->last_frame()) {
3323 double times = (double) (end - region->last_frame()) / (double) region->length();
3330 begin_reversible_command (Operations::region_fill);
3333 TimeAxisView& tv = (*i)->get_time_axis_view();
3334 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3335 latest_regionviews.clear ();
3336 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3338 pl->clear_changes ();
3339 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3340 _session->add_command (new StatefulDiffCommand (pl));
3344 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3349 selection->set (foo);
3351 commit_reversible_command ();
3356 Editor::region_fill_selection ()
3358 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3362 if (selection->time.empty()) {
3366 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3371 framepos_t start = selection->time[clicked_selection].start;
3372 framepos_t end = selection->time[clicked_selection].end;
3374 boost::shared_ptr<Playlist> playlist;
3376 if (selection->tracks.empty()) {
3380 framepos_t selection_length = end - start;
3381 float times = (float)selection_length / region->length();
3382 bool in_command = false;
3384 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3385 RegionSelection foo;
3387 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3389 if ((playlist = (*i)->playlist()) == 0) {
3394 begin_reversible_command (Operations::fill_selection);
3397 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3398 latest_regionviews.clear ();
3399 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3401 playlist->clear_changes ();
3402 playlist->add_region (RegionFactory::create (region, true), start, times);
3403 _session->add_command (new StatefulDiffCommand (playlist));
3405 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3410 selection->set (foo);
3412 commit_reversible_command ();
3417 Editor::set_region_sync_position ()
3419 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3423 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3425 bool in_command = false;
3427 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3429 if (!(*r)->region()->covers (where)) {
3433 boost::shared_ptr<Region> region ((*r)->region());
3436 begin_reversible_command (_("set sync point"));
3440 region->clear_changes ();
3441 region->set_sync_position (where);
3442 _session->add_command(new StatefulDiffCommand (region));
3446 commit_reversible_command ();
3450 /** Remove the sync positions of the selection */
3452 Editor::remove_region_sync ()
3454 RegionSelection rs = get_regions_from_selection_and_entered ();
3460 begin_reversible_command (_("remove region sync"));
3462 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3464 (*i)->region()->clear_changes ();
3465 (*i)->region()->clear_sync_position ();
3466 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3469 commit_reversible_command ();
3473 Editor::naturalize_region ()
3475 RegionSelection rs = get_regions_from_selection_and_entered ();
3481 if (rs.size() > 1) {
3482 begin_reversible_command (_("move regions to original position"));
3484 begin_reversible_command (_("move region to original position"));
3487 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3488 (*i)->region()->clear_changes ();
3489 (*i)->region()->move_to_natural_position ();
3490 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3493 commit_reversible_command ();
3497 Editor::align_regions (RegionPoint what)
3499 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3505 begin_reversible_command (_("align selection"));
3507 framepos_t const position = get_preferred_edit_position ();
3509 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3510 align_region_internal ((*i)->region(), what, position);
3513 commit_reversible_command ();
3516 struct RegionSortByTime {
3517 bool operator() (const RegionView* a, const RegionView* b) {
3518 return a->region()->position() < b->region()->position();
3523 Editor::align_regions_relative (RegionPoint point)
3525 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3531 framepos_t const position = get_preferred_edit_position ();
3533 framepos_t distance = 0;
3537 list<RegionView*> sorted;
3538 rs.by_position (sorted);
3540 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3545 if (position > r->position()) {
3546 distance = position - r->position();
3548 distance = r->position() - position;
3554 if (position > r->last_frame()) {
3555 distance = position - r->last_frame();
3556 pos = r->position() + distance;
3558 distance = r->last_frame() - position;
3559 pos = r->position() - distance;
3565 pos = r->adjust_to_sync (position);
3566 if (pos > r->position()) {
3567 distance = pos - r->position();
3569 distance = r->position() - pos;
3575 if (pos == r->position()) {
3579 begin_reversible_command (_("align selection (relative)"));
3581 /* move first one specially */
3583 r->clear_changes ();
3584 r->set_position (pos);
3585 _session->add_command(new StatefulDiffCommand (r));
3587 /* move rest by the same amount */
3591 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3593 boost::shared_ptr<Region> region ((*i)->region());
3595 region->clear_changes ();
3598 region->set_position (region->position() + distance);
3600 region->set_position (region->position() - distance);
3603 _session->add_command(new StatefulDiffCommand (region));
3607 commit_reversible_command ();
3611 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3613 begin_reversible_command (_("align region"));
3614 align_region_internal (region, point, position);
3615 commit_reversible_command ();
3619 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3621 region->clear_changes ();
3625 region->set_position (region->adjust_to_sync (position));
3629 if (position > region->length()) {
3630 region->set_position (position - region->length());
3635 region->set_position (position);
3639 _session->add_command(new StatefulDiffCommand (region));
3643 Editor::trim_region_front ()
3649 Editor::trim_region_back ()
3651 trim_region (false);
3655 Editor::trim_region (bool front)
3657 framepos_t where = get_preferred_edit_position();
3658 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3664 begin_reversible_command (front ? _("trim front") : _("trim back"));
3666 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3667 if (!(*i)->region()->locked()) {
3669 (*i)->region()->clear_changes ();
3672 (*i)->region()->trim_front (where);
3673 maybe_locate_with_edit_preroll ( where );
3675 (*i)->region()->trim_end (where);
3676 maybe_locate_with_edit_preroll ( where );
3679 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3683 commit_reversible_command ();
3686 /** Trim the end of the selected regions to the position of the edit cursor */
3688 Editor::trim_region_to_loop ()
3690 Location* loc = _session->locations()->auto_loop_location();
3694 trim_region_to_location (*loc, _("trim to loop"));
3698 Editor::trim_region_to_punch ()
3700 Location* loc = _session->locations()->auto_punch_location();
3704 trim_region_to_location (*loc, _("trim to punch"));
3708 Editor::trim_region_to_location (const Location& loc, const char* str)
3710 RegionSelection rs = get_regions_from_selection_and_entered ();
3711 bool in_command = false;
3713 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3714 RegionView* rv = (*x);
3716 /* require region to span proposed trim */
3717 switch (rv->region()->coverage (loc.start(), loc.end())) {
3718 case Evoral::OverlapInternal:
3724 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3733 if (tav->track() != 0) {
3734 speed = tav->track()->speed();
3737 start = session_frame_to_track_frame (loc.start(), speed);
3738 end = session_frame_to_track_frame (loc.end(), speed);
3740 rv->region()->clear_changes ();
3741 rv->region()->trim_to (start, (end - start));
3744 begin_reversible_command (str);
3747 _session->add_command(new StatefulDiffCommand (rv->region()));
3751 commit_reversible_command ();
3756 Editor::trim_region_to_previous_region_end ()
3758 return trim_to_region(false);
3762 Editor::trim_region_to_next_region_start ()
3764 return trim_to_region(true);
3768 Editor::trim_to_region(bool forward)
3770 RegionSelection rs = get_regions_from_selection_and_entered ();
3771 bool in_command = false;
3773 boost::shared_ptr<Region> next_region;
3775 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3777 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3783 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3791 if (atav->track() != 0) {
3792 speed = atav->track()->speed();
3796 boost::shared_ptr<Region> region = arv->region();
3797 boost::shared_ptr<Playlist> playlist (region->playlist());
3799 region->clear_changes ();
3803 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3809 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3810 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3814 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3820 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3822 arv->region_changed (ARDOUR::bounds_change);
3826 begin_reversible_command (_("trim to region"));
3829 _session->add_command(new StatefulDiffCommand (region));
3833 commit_reversible_command ();
3838 Editor::unfreeze_route ()
3840 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3844 clicked_routeview->track()->unfreeze ();
3848 Editor::_freeze_thread (void* arg)
3850 return static_cast<Editor*>(arg)->freeze_thread ();
3854 Editor::freeze_thread ()
3856 /* create event pool because we may need to talk to the session */
3857 SessionEvent::create_per_thread_pool ("freeze events", 64);
3858 /* create per-thread buffers for process() tree to use */
3859 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3860 current_interthread_info->done = true;
3865 Editor::freeze_route ()
3871 /* stop transport before we start. this is important */
3873 _session->request_transport_speed (0.0);
3875 /* wait for just a little while, because the above call is asynchronous */
3877 Glib::usleep (250000);
3879 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3883 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3885 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3886 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3888 d.set_title (_("Cannot freeze"));
3893 if (clicked_routeview->track()->has_external_redirects()) {
3894 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"
3895 "Freezing will only process the signal as far as the first send/insert/return."),
3896 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3898 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3899 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3900 d.set_title (_("Freeze Limits"));
3902 int response = d.run ();
3905 case Gtk::RESPONSE_CANCEL:
3912 InterThreadInfo itt;
3913 current_interthread_info = &itt;
3915 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3917 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3919 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3921 while (!itt.done && !itt.cancel) {
3922 gtk_main_iteration ();
3925 current_interthread_info = 0;
3929 Editor::bounce_range_selection (bool replace, bool enable_processing)
3931 if (selection->time.empty()) {
3935 TrackSelection views = selection->tracks;
3937 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3939 if (enable_processing) {
3941 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3943 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3945 _("You can't perform this operation because the processing of the signal "
3946 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3947 "You can do this without processing, which is a different operation.")
3949 d.set_title (_("Cannot bounce"));
3956 framepos_t start = selection->time[clicked_selection].start;
3957 framepos_t end = selection->time[clicked_selection].end;
3958 framepos_t cnt = end - start + 1;
3959 bool in_command = false;
3961 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3963 RouteTimeAxisView* rtv;
3965 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3969 boost::shared_ptr<Playlist> playlist;
3971 if ((playlist = rtv->playlist()) == 0) {
3975 InterThreadInfo itt;
3977 playlist->clear_changes ();
3978 playlist->clear_owned_changes ();
3980 boost::shared_ptr<Region> r;
3982 if (enable_processing) {
3983 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3985 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3993 list<AudioRange> ranges;
3994 ranges.push_back (AudioRange (start, start+cnt, 0));
3995 playlist->cut (ranges); // discard result
3996 playlist->add_region (r, start);
4000 begin_reversible_command (_("bounce range"));
4003 vector<Command*> cmds;
4004 playlist->rdiff (cmds);
4005 _session->add_commands (cmds);
4007 _session->add_command (new StatefulDiffCommand (playlist));
4011 commit_reversible_command ();
4015 /** Delete selected regions, automation points or a time range */
4019 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4020 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4021 bool deleted = false;
4022 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4023 deleted = current_mixer_strip->delete_processors ();
4029 /** Cut selected regions, automation points or a time range */
4036 /** Copy selected regions, automation points or a time range */
4044 /** @return true if a Cut, Copy or Clear is possible */
4046 Editor::can_cut_copy () const
4048 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4055 /** Cut, copy or clear selected regions, automation points or a time range.
4056 * @param op Operation (Delete, Cut, Copy or Clear)
4059 Editor::cut_copy (CutCopyOp op)
4061 /* only cancel selection if cut/copy is successful.*/
4067 opname = _("delete");
4076 opname = _("clear");
4080 /* if we're deleting something, and the mouse is still pressed,
4081 the thing we started a drag for will be gone when we release
4082 the mouse button(s). avoid this. see part 2 at the end of
4086 if (op == Delete || op == Cut || op == Clear) {
4087 if (_drags->active ()) {
4092 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4093 cut_buffer->clear ();
4095 if (entered_marker) {
4097 /* cut/delete op while pointing at a marker */
4100 Location* loc = find_location_from_marker (entered_marker, ignored);
4102 if (_session && loc) {
4103 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4110 switch (mouse_mode) {
4113 begin_reversible_command (opname + ' ' + X_("MIDI"));
4115 commit_reversible_command ();
4121 bool did_edit = false;
4123 if (!selection->regions.empty() || !selection->points.empty()) {
4124 begin_reversible_command (opname + ' ' + _("objects"));
4127 if (!selection->regions.empty()) {
4128 cut_copy_regions (op, selection->regions);
4130 if (op == Cut || op == Delete) {
4131 selection->clear_regions ();
4135 if (!selection->points.empty()) {
4136 cut_copy_points (op);
4138 if (op == Cut || op == Delete) {
4139 selection->clear_points ();
4142 } else if (selection->time.empty()) {
4143 framepos_t start, end;
4144 /* no time selection, see if we can get an edit range
4147 if (get_edit_op_range (start, end)) {
4148 selection->set (start, end);
4150 } else if (!selection->time.empty()) {
4151 begin_reversible_command (opname + ' ' + _("range"));
4154 cut_copy_ranges (op);
4156 if (op == Cut || op == Delete) {
4157 selection->clear_time ();
4162 /* reset repeated paste state */
4165 commit_reversible_command ();
4168 if (op == Delete || op == Cut || op == Clear) {
4173 struct AutomationRecord {
4174 AutomationRecord () : state (0) , line(NULL) {}
4175 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4177 XMLNode* state; ///< state before any operation
4178 const AutomationLine* line; ///< line this came from
4179 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4182 /** Cut, copy or clear selected automation points.
4183 * @param op Operation (Cut, Copy or Clear)
4186 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4188 if (selection->points.empty ()) {
4192 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4193 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4195 /* Keep a record of the AutomationLists that we end up using in this operation */
4196 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4199 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4200 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4201 const AutomationLine& line = (*i)->line();
4202 const boost::shared_ptr<AutomationList> al = line.the_list();
4203 if (lists.find (al) == lists.end ()) {
4204 /* We haven't seen this list yet, so make a record for it. This includes
4205 taking a copy of its current state, in case this is needed for undo later.
4207 lists[al] = AutomationRecord (&al->get_state (), &line);
4211 if (op == Cut || op == Copy) {
4212 /* This operation will involve putting things in the cut buffer, so create an empty
4213 ControlList for each of our source lists to put the cut buffer data in.
4215 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4216 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4219 /* Add all selected points to the relevant copy ControlLists */
4220 framepos_t start = std::numeric_limits<framepos_t>::max();
4221 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4222 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4223 AutomationList::const_iterator j = (*i)->model();
4225 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4227 /* Update earliest MIDI start time in beats */
4228 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4230 /* Update earliest session start time in frames */
4231 start = std::min(start, (*i)->line().session_position(j));
4235 /* Snap start time backwards, so copy/paste is snap aligned. */
4237 if (earliest == Evoral::Beats::max()) {
4238 earliest = Evoral::Beats(); // Weird... don't offset
4240 earliest.round_down_to_beat();
4242 if (start == std::numeric_limits<double>::max()) {
4243 start = 0; // Weird... don't offset
4245 snap_to(start, RoundDownMaybe);
4248 const double line_offset = midi ? earliest.to_double() : start;
4249 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4250 /* Correct this copy list so that it is relative to the earliest
4251 start time, so relative ordering between points is preserved
4252 when copying from several lists and the paste starts at the
4253 earliest copied piece of data. */
4254 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4255 (*j)->when -= line_offset;
4258 /* And add it to the cut buffer */
4259 cut_buffer->add (i->second.copy);
4263 if (op == Delete || op == Cut) {
4264 /* This operation needs to remove things from the main AutomationList, so do that now */
4266 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4267 i->first->freeze ();
4270 /* Remove each selected point from its AutomationList */
4271 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4272 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4273 al->erase ((*i)->model ());
4276 /* Thaw the lists and add undo records for them */
4277 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4278 boost::shared_ptr<AutomationList> al = i->first;
4280 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4285 /** Cut, copy or clear selected automation points.
4286 * @param op Operation (Cut, Copy or Clear)
4289 Editor::cut_copy_midi (CutCopyOp op)
4291 Evoral::Beats earliest = Evoral::Beats::max();
4292 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4293 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4295 if (!mrv->selection().empty()) {
4296 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4298 mrv->cut_copy_clear (op);
4300 /* XXX: not ideal, as there may be more than one track involved in the selection */
4301 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4305 if (!selection->points.empty()) {
4306 cut_copy_points (op, earliest, true);
4307 if (op == Cut || op == Delete) {
4308 selection->clear_points ();
4313 struct lt_playlist {
4314 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4315 return a.playlist < b.playlist;
4319 struct PlaylistMapping {
4321 boost::shared_ptr<Playlist> pl;
4323 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4326 /** Remove `clicked_regionview' */
4328 Editor::remove_clicked_region ()
4330 if (clicked_routeview == 0 || clicked_regionview == 0) {
4334 begin_reversible_command (_("remove region"));
4336 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4338 playlist->clear_changes ();
4339 playlist->clear_owned_changes ();
4340 playlist->remove_region (clicked_regionview->region());
4341 if (Config->get_edit_mode() == Ripple)
4342 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4344 /* We might have removed regions, which alters other regions' layering_index,
4345 so we need to do a recursive diff here.
4347 vector<Command*> cmds;
4348 playlist->rdiff (cmds);
4349 _session->add_commands (cmds);
4351 _session->add_command(new StatefulDiffCommand (playlist));
4352 commit_reversible_command ();
4356 /** Remove the selected regions */
4358 Editor::remove_selected_regions ()
4360 RegionSelection rs = get_regions_from_selection_and_entered ();
4362 if (!_session || rs.empty()) {
4366 list<boost::shared_ptr<Region> > regions_to_remove;
4368 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4369 // we can't just remove the region(s) in this loop because
4370 // this removes them from the RegionSelection, and they thus
4371 // disappear from underneath the iterator, and the ++i above
4372 // SEGVs in a puzzling fashion.
4374 // so, first iterate over the regions to be removed from rs and
4375 // add them to the regions_to_remove list, and then
4376 // iterate over the list to actually remove them.
4378 regions_to_remove.push_back ((*i)->region());
4381 vector<boost::shared_ptr<Playlist> > playlists;
4383 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4385 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4388 // is this check necessary?
4392 /* get_regions_from_selection_and_entered() guarantees that
4393 the playlists involved are unique, so there is no need
4397 playlists.push_back (playlist);
4399 playlist->clear_changes ();
4400 playlist->clear_owned_changes ();
4401 playlist->freeze ();
4402 playlist->remove_region (*rl);
4403 if (Config->get_edit_mode() == Ripple)
4404 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4408 vector<boost::shared_ptr<Playlist> >::iterator pl;
4409 bool in_command = false;
4411 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4414 /* We might have removed regions, which alters other regions' layering_index,
4415 so we need to do a recursive diff here.
4419 begin_reversible_command (_("remove region"));
4422 vector<Command*> cmds;
4423 (*pl)->rdiff (cmds);
4424 _session->add_commands (cmds);
4426 _session->add_command(new StatefulDiffCommand (*pl));
4430 commit_reversible_command ();
4434 /** Cut, copy or clear selected regions.
4435 * @param op Operation (Cut, Copy or Clear)
4438 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4440 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4441 a map when we want ordered access to both elements. i think.
4444 vector<PlaylistMapping> pmap;
4446 framepos_t first_position = max_framepos;
4448 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4449 FreezeList freezelist;
4451 /* get ordering correct before we cut/copy */
4453 rs.sort_by_position_and_track ();
4455 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4457 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4459 if (op == Cut || op == Clear || op == Delete) {
4460 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4463 FreezeList::iterator fl;
4465 // only take state if this is a new playlist.
4466 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4472 if (fl == freezelist.end()) {
4473 pl->clear_changes();
4474 pl->clear_owned_changes ();
4476 freezelist.insert (pl);
4481 TimeAxisView* tv = &(*x)->get_time_axis_view();
4482 vector<PlaylistMapping>::iterator z;
4484 for (z = pmap.begin(); z != pmap.end(); ++z) {
4485 if ((*z).tv == tv) {
4490 if (z == pmap.end()) {
4491 pmap.push_back (PlaylistMapping (tv));
4495 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4497 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4500 /* region not yet associated with a playlist (e.g. unfinished
4507 TimeAxisView& tv = (*x)->get_time_axis_view();
4508 boost::shared_ptr<Playlist> npl;
4509 RegionSelection::iterator tmp;
4516 vector<PlaylistMapping>::iterator z;
4518 for (z = pmap.begin(); z != pmap.end(); ++z) {
4519 if ((*z).tv == &tv) {
4524 assert (z != pmap.end());
4527 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4535 boost::shared_ptr<Region> r = (*x)->region();
4536 boost::shared_ptr<Region> _xx;
4542 pl->remove_region (r);
4543 if (Config->get_edit_mode() == Ripple)
4544 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4548 _xx = RegionFactory::create (r);
4549 npl->add_region (_xx, r->position() - first_position);
4550 pl->remove_region (r);
4551 if (Config->get_edit_mode() == Ripple)
4552 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4556 /* copy region before adding, so we're not putting same object into two different playlists */
4557 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4561 pl->remove_region (r);
4562 if (Config->get_edit_mode() == Ripple)
4563 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4572 list<boost::shared_ptr<Playlist> > foo;
4574 /* the pmap is in the same order as the tracks in which selected regions occured */
4576 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4579 foo.push_back ((*i).pl);
4584 cut_buffer->set (foo);
4588 _last_cut_copy_source_track = 0;
4590 _last_cut_copy_source_track = pmap.front().tv;
4594 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4597 /* We might have removed regions, which alters other regions' layering_index,
4598 so we need to do a recursive diff here.
4600 vector<Command*> cmds;
4601 (*pl)->rdiff (cmds);
4602 _session->add_commands (cmds);
4604 _session->add_command (new StatefulDiffCommand (*pl));
4609 Editor::cut_copy_ranges (CutCopyOp op)
4611 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4613 /* Sort the track selection now, so that it if is used, the playlists
4614 selected by the calls below to cut_copy_clear are in the order that
4615 their tracks appear in the editor. This makes things like paste
4616 of ranges work properly.
4619 sort_track_selection (ts);
4622 if (!entered_track) {
4625 ts.push_back (entered_track);
4628 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4629 (*i)->cut_copy_clear (*selection, op);
4634 Editor::paste (float times, bool from_context)
4636 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4638 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4642 Editor::mouse_paste ()
4647 if (!mouse_frame (where, ignored)) {
4652 paste_internal (where, 1);
4656 Editor::paste_internal (framepos_t position, float times)
4658 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4660 if (cut_buffer->empty(internal_editing())) {
4664 if (position == max_framepos) {
4665 position = get_preferred_edit_position();
4666 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4669 if (position == last_paste_pos) {
4670 /* repeated paste in the same position */
4673 /* paste in new location, reset repeated paste state */
4675 last_paste_pos = position;
4678 /* get everything in the correct order */
4681 if (!selection->tracks.empty()) {
4682 /* If there is a track selection, paste into exactly those tracks and
4683 only those tracks. This allows the user to be explicit and override
4684 the below "do the reasonable thing" logic. */
4685 ts = selection->tracks.filter_to_unique_playlists ();
4686 sort_track_selection (ts);
4688 /* Figure out which track to base the paste at. */
4689 TimeAxisView* base_track = NULL;
4690 if (_edit_point == Editing::EditAtMouse && entered_track) {
4691 /* With the mouse edit point, paste onto the track under the mouse. */
4692 base_track = entered_track;
4693 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4694 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4695 base_track = &entered_regionview->get_time_axis_view();
4696 } else if (_last_cut_copy_source_track) {
4697 /* Paste to the track that the cut/copy came from (see mantis #333). */
4698 base_track = _last_cut_copy_source_track;
4700 /* This is "impossible" since we've copied... well, do nothing. */
4704 /* Walk up to parent if necessary, so base track is a route. */
4705 while (base_track->get_parent()) {
4706 base_track = base_track->get_parent();
4709 /* Add base track and all tracks below it. The paste logic will select
4710 the appropriate object types from the cut buffer in relative order. */
4711 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4712 if ((*i)->order() >= base_track->order()) {
4717 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4718 sort_track_selection (ts);
4720 /* Add automation children of each track in order, for pasting several lines. */
4721 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4722 /* Add any automation children for pasting several lines */
4723 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4728 typedef RouteTimeAxisView::AutomationTracks ATracks;
4729 const ATracks& atracks = rtv->automation_tracks();
4730 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4731 i = ts.insert(i, a->second.get());
4736 /* We now have a list of trackviews starting at base_track, including
4737 automation children, in the order shown in the editor, e.g. R1,
4738 R1.A1, R1.A2, R2, R2.A1, ... */
4741 begin_reversible_command (Operations::paste);
4743 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4744 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4745 /* Only one line copied, and one automation track selected. Do a
4746 "greedy" paste from one automation type to another. */
4748 PasteContext ctx(paste_count, times, ItemCounts(), true);
4749 ts.front()->paste (position, *cut_buffer, ctx);
4753 /* Paste into tracks */
4755 PasteContext ctx(paste_count, times, ItemCounts(), false);
4756 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4757 (*i)->paste (position, *cut_buffer, ctx);
4761 commit_reversible_command ();
4765 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4767 if (regions.empty ()) {
4771 boost::shared_ptr<Playlist> playlist;
4772 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4773 RegionSelection foo;
4775 framepos_t const start_frame = regions.start ();
4776 framepos_t const end_frame = regions.end_frame ();
4777 framecnt_t const gap = end_frame - start_frame;
4779 begin_reversible_command (Operations::duplicate_region);
4781 selection->clear_regions ();
4783 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4785 boost::shared_ptr<Region> r ((*i)->region());
4787 TimeAxisView& tv = (*i)->get_time_axis_view();
4788 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4789 latest_regionviews.clear ();
4790 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4792 framepos_t const position = end_frame + (r->first_frame() - start_frame);
4793 playlist = (*i)->region()->playlist();
4794 playlist->clear_changes ();
4795 playlist->duplicate (r, position, gap, times);
4796 _session->add_command(new StatefulDiffCommand (playlist));
4800 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4804 selection->set (foo);
4807 commit_reversible_command ();
4811 Editor::duplicate_selection (float times)
4813 if (selection->time.empty() || selection->tracks.empty()) {
4817 boost::shared_ptr<Playlist> playlist;
4818 vector<boost::shared_ptr<Region> > new_regions;
4819 vector<boost::shared_ptr<Region> >::iterator ri;
4821 create_region_from_selection (new_regions);
4823 if (new_regions.empty()) {
4827 ri = new_regions.begin();
4829 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4830 bool in_command = false;
4832 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4833 if ((playlist = (*i)->playlist()) == 0) {
4836 playlist->clear_changes ();
4838 if (clicked_selection) {
4839 end = selection->time[clicked_selection].end;
4841 end = selection->time.end_frame();
4843 playlist->duplicate (*ri, end, times);
4846 begin_reversible_command (_("duplicate selection"));
4849 _session->add_command (new StatefulDiffCommand (playlist));
4852 if (ri == new_regions.end()) {
4858 commit_reversible_command ();
4862 /** Reset all selected points to the relevant default value */
4864 Editor::reset_point_selection ()
4866 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4867 ARDOUR::AutomationList::iterator j = (*i)->model ();
4868 (*j)->value = (*i)->line().the_list()->default_value ();
4873 Editor::center_playhead ()
4875 float const page = _visible_canvas_width * samples_per_pixel;
4876 center_screen_internal (playhead_cursor->current_frame (), page);
4880 Editor::center_edit_point ()
4882 float const page = _visible_canvas_width * samples_per_pixel;
4883 center_screen_internal (get_preferred_edit_position(), page);
4886 /** Caller must begin and commit a reversible command */
4888 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4890 playlist->clear_changes ();
4892 _session->add_command (new StatefulDiffCommand (playlist));
4896 Editor::nudge_track (bool use_edit, bool forwards)
4898 boost::shared_ptr<Playlist> playlist;
4899 framepos_t distance;
4900 framepos_t next_distance;
4904 start = get_preferred_edit_position();
4909 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4913 if (selection->tracks.empty()) {
4917 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4918 bool in_command = false;
4920 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4922 if ((playlist = (*i)->playlist()) == 0) {
4926 playlist->clear_changes ();
4927 playlist->clear_owned_changes ();
4929 playlist->nudge_after (start, distance, forwards);
4932 begin_reversible_command (_("nudge track"));
4935 vector<Command*> cmds;
4937 playlist->rdiff (cmds);
4938 _session->add_commands (cmds);
4940 _session->add_command (new StatefulDiffCommand (playlist));
4944 commit_reversible_command ();
4949 Editor::remove_last_capture ()
4951 vector<string> choices;
4958 if (Config->get_verify_remove_last_capture()) {
4959 prompt = _("Do you really want to destroy the last capture?"
4960 "\n(This is destructive and cannot be undone)");
4962 choices.push_back (_("No, do nothing."));
4963 choices.push_back (_("Yes, destroy it."));
4965 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4967 if (prompter.run () == 1) {
4968 _session->remove_last_capture ();
4969 _regions->redisplay ();
4973 _session->remove_last_capture();
4974 _regions->redisplay ();
4979 Editor::normalize_region ()
4985 RegionSelection rs = get_regions_from_selection_and_entered ();
4991 NormalizeDialog dialog (rs.size() > 1);
4993 if (dialog.run () == RESPONSE_CANCEL) {
4997 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5000 /* XXX: should really only count audio regions here */
5001 int const regions = rs.size ();
5003 /* Make a list of the selected audio regions' maximum amplitudes, and also
5004 obtain the maximum amplitude of them all.
5006 list<double> max_amps;
5008 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5009 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5011 dialog.descend (1.0 / regions);
5012 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5015 /* the user cancelled the operation */
5019 max_amps.push_back (a);
5020 max_amp = max (max_amp, a);
5025 list<double>::const_iterator a = max_amps.begin ();
5026 bool in_command = false;
5028 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5029 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5034 arv->region()->clear_changes ();
5036 double const amp = dialog.normalize_individually() ? *a : max_amp;
5038 arv->audio_region()->normalize (amp, dialog.target ());
5041 begin_reversible_command (_("normalize"));
5044 _session->add_command (new StatefulDiffCommand (arv->region()));
5050 commit_reversible_command ();
5056 Editor::reset_region_scale_amplitude ()
5062 RegionSelection rs = get_regions_from_selection_and_entered ();
5068 bool in_command = false;
5070 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5071 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5074 arv->region()->clear_changes ();
5075 arv->audio_region()->set_scale_amplitude (1.0f);
5078 begin_reversible_command ("reset gain");
5081 _session->add_command (new StatefulDiffCommand (arv->region()));
5085 commit_reversible_command ();
5090 Editor::adjust_region_gain (bool up)
5092 RegionSelection rs = get_regions_from_selection_and_entered ();
5094 if (!_session || rs.empty()) {
5098 bool in_command = false;
5100 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5101 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5106 arv->region()->clear_changes ();
5108 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5116 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5119 begin_reversible_command ("adjust region gain");
5122 _session->add_command (new StatefulDiffCommand (arv->region()));
5126 commit_reversible_command ();
5132 Editor::reverse_region ()
5138 Reverse rev (*_session);
5139 apply_filter (rev, _("reverse regions"));
5143 Editor::strip_region_silence ()
5149 RegionSelection rs = get_regions_from_selection_and_entered ();
5155 std::list<RegionView*> audio_only;
5157 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5158 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5160 audio_only.push_back (arv);
5164 assert (!audio_only.empty());
5166 StripSilenceDialog d (_session, audio_only);
5167 int const r = d.run ();
5171 if (r == Gtk::RESPONSE_OK) {
5172 ARDOUR::AudioIntervalMap silences;
5173 d.silences (silences);
5174 StripSilence s (*_session, silences, d.fade_length());
5175 apply_filter (s, _("strip silence"), &d);
5180 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5182 Evoral::Sequence<Evoral::Beats>::Notes selected;
5183 mrv.selection_as_notelist (selected, true);
5185 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5186 v.push_back (selected);
5188 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5189 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5191 return op (mrv.midi_region()->model(), pos_beats, v);
5195 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5201 bool in_command = false;
5203 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5204 RegionSelection::const_iterator tmp = r;
5207 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5210 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5213 begin_reversible_command (op.name ());
5217 _session->add_command (cmd);
5225 commit_reversible_command ();
5230 Editor::fork_region ()
5232 RegionSelection rs = get_regions_from_selection_and_entered ();
5238 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5239 bool in_command = false;
5243 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5244 RegionSelection::iterator tmp = r;
5247 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5251 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5252 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5253 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5256 begin_reversible_command (_("Fork Region(s)"));
5259 playlist->clear_changes ();
5260 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5261 _session->add_command(new StatefulDiffCommand (playlist));
5263 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5271 commit_reversible_command ();
5276 Editor::quantize_region ()
5279 quantize_regions(get_regions_from_selection_and_entered ());
5284 Editor::quantize_regions (const RegionSelection& rs)
5286 if (rs.n_midi_regions() == 0) {
5290 if (!quantize_dialog) {
5291 quantize_dialog = new QuantizeDialog (*this);
5294 quantize_dialog->present ();
5295 const int r = quantize_dialog->run ();
5296 quantize_dialog->hide ();
5298 if (r == Gtk::RESPONSE_OK) {
5299 Quantize quant (quantize_dialog->snap_start(),
5300 quantize_dialog->snap_end(),
5301 quantize_dialog->start_grid_size(),
5302 quantize_dialog->end_grid_size(),
5303 quantize_dialog->strength(),
5304 quantize_dialog->swing(),
5305 quantize_dialog->threshold());
5307 apply_midi_note_edit_op (quant, rs);
5312 Editor::legatize_region (bool shrink_only)
5315 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5320 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5322 if (rs.n_midi_regions() == 0) {
5326 Legatize legatize(shrink_only);
5327 apply_midi_note_edit_op (legatize, rs);
5331 Editor::transform_region ()
5334 transform_regions(get_regions_from_selection_and_entered ());
5339 Editor::transform_regions (const RegionSelection& rs)
5341 if (rs.n_midi_regions() == 0) {
5348 const int r = td.run();
5351 if (r == Gtk::RESPONSE_OK) {
5352 Transform transform(td.get());
5353 apply_midi_note_edit_op(transform, rs);
5358 Editor::transpose_region ()
5361 transpose_regions(get_regions_from_selection_and_entered ());
5366 Editor::transpose_regions (const RegionSelection& rs)
5368 if (rs.n_midi_regions() == 0) {
5373 int const r = d.run ();
5375 if (r == RESPONSE_ACCEPT) {
5376 Transpose transpose(d.semitones ());
5377 apply_midi_note_edit_op (transpose, rs);
5382 Editor::insert_patch_change (bool from_context)
5384 RegionSelection rs = get_regions_from_selection_and_entered ();
5390 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5392 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5393 there may be more than one, but the PatchChangeDialog can only offer
5394 one set of patch menus.
5396 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5398 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5399 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5401 if (d.run() == RESPONSE_CANCEL) {
5405 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5406 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5408 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5409 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5416 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5418 RegionSelection rs = get_regions_from_selection_and_entered ();
5424 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5425 bool in_command = false;
5430 int const N = rs.size ();
5432 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5433 RegionSelection::iterator tmp = r;
5436 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5438 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5441 progress->descend (1.0 / N);
5444 if (arv->audio_region()->apply (filter, progress) == 0) {
5446 playlist->clear_changes ();
5447 playlist->clear_owned_changes ();
5449 if (filter.results.empty ()) {
5451 /* no regions returned; remove the old one */
5452 playlist->remove_region (arv->region ());
5456 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5458 /* first region replaces the old one */
5459 playlist->replace_region (arv->region(), *res, (*res)->position());
5463 while (res != filter.results.end()) {
5464 playlist->add_region (*res, (*res)->position());
5469 /* We might have removed regions, which alters other regions' layering_index,
5470 so we need to do a recursive diff here.
5474 begin_reversible_command (command);
5477 vector<Command*> cmds;
5478 playlist->rdiff (cmds);
5479 _session->add_commands (cmds);
5481 _session->add_command(new StatefulDiffCommand (playlist));
5485 progress->ascend ();
5494 commit_reversible_command ();
5499 Editor::external_edit_region ()
5505 Editor::reset_region_gain_envelopes ()
5507 RegionSelection rs = get_regions_from_selection_and_entered ();
5509 if (!_session || rs.empty()) {
5513 bool in_command = false;
5515 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5516 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5518 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5519 XMLNode& before (alist->get_state());
5521 arv->audio_region()->set_default_envelope ();
5524 begin_reversible_command (_("reset region gain"));
5527 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5532 commit_reversible_command ();
5537 Editor::set_region_gain_visibility (RegionView* rv)
5539 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5541 arv->update_envelope_visibility();
5546 Editor::set_gain_envelope_visibility ()
5552 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5553 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5555 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5561 Editor::toggle_gain_envelope_active ()
5563 if (_ignore_region_action) {
5567 RegionSelection rs = get_regions_from_selection_and_entered ();
5569 if (!_session || rs.empty()) {
5573 bool in_command = false;
5575 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5576 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5578 arv->region()->clear_changes ();
5579 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5582 begin_reversible_command (_("region gain envelope active"));
5585 _session->add_command (new StatefulDiffCommand (arv->region()));
5590 commit_reversible_command ();
5595 Editor::toggle_region_lock ()
5597 if (_ignore_region_action) {
5601 RegionSelection rs = get_regions_from_selection_and_entered ();
5603 if (!_session || rs.empty()) {
5607 begin_reversible_command (_("toggle region lock"));
5609 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5610 (*i)->region()->clear_changes ();
5611 (*i)->region()->set_locked (!(*i)->region()->locked());
5612 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5615 commit_reversible_command ();
5619 Editor::toggle_region_video_lock ()
5621 if (_ignore_region_action) {
5625 RegionSelection rs = get_regions_from_selection_and_entered ();
5627 if (!_session || rs.empty()) {
5631 begin_reversible_command (_("Toggle Video Lock"));
5633 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5634 (*i)->region()->clear_changes ();
5635 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5636 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5639 commit_reversible_command ();
5643 Editor::toggle_region_lock_style ()
5645 if (_ignore_region_action) {
5649 RegionSelection rs = get_regions_from_selection_and_entered ();
5651 if (!_session || rs.empty()) {
5655 begin_reversible_command (_("region lock style"));
5657 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5658 (*i)->region()->clear_changes ();
5659 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5660 (*i)->region()->set_position_lock_style (ns);
5661 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5664 commit_reversible_command ();
5668 Editor::toggle_opaque_region ()
5670 if (_ignore_region_action) {
5674 RegionSelection rs = get_regions_from_selection_and_entered ();
5676 if (!_session || rs.empty()) {
5680 begin_reversible_command (_("change region opacity"));
5682 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5683 (*i)->region()->clear_changes ();
5684 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5685 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5688 commit_reversible_command ();
5692 Editor::toggle_record_enable ()
5694 bool new_state = false;
5696 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5697 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5700 if (!rtav->is_track())
5704 new_state = !rtav->track()->record_enabled();
5708 rtav->track()->set_record_enabled (new_state, this);
5713 Editor::toggle_solo ()
5715 bool new_state = false;
5717 boost::shared_ptr<RouteList> rl (new RouteList);
5719 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5720 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5727 new_state = !rtav->route()->soloed ();
5731 rl->push_back (rtav->route());
5734 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5738 Editor::toggle_mute ()
5740 bool new_state = false;
5742 boost::shared_ptr<RouteList> rl (new RouteList);
5744 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5745 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5752 new_state = !rtav->route()->muted();
5756 rl->push_back (rtav->route());
5759 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5763 Editor::toggle_solo_isolate ()
5769 Editor::fade_range ()
5771 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5773 begin_reversible_command (_("fade range"));
5775 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5776 (*i)->fade_range (selection->time);
5779 commit_reversible_command ();
5784 Editor::set_fade_length (bool in)
5786 RegionSelection rs = get_regions_from_selection_and_entered ();
5792 /* we need a region to measure the offset from the start */
5794 RegionView* rv = rs.front ();
5796 framepos_t pos = get_preferred_edit_position();
5800 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5801 /* edit point is outside the relevant region */
5806 if (pos <= rv->region()->position()) {
5810 len = pos - rv->region()->position();
5811 cmd = _("set fade in length");
5813 if (pos >= rv->region()->last_frame()) {
5817 len = rv->region()->last_frame() - pos;
5818 cmd = _("set fade out length");
5821 bool in_command = false;
5823 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5824 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5830 boost::shared_ptr<AutomationList> alist;
5832 alist = tmp->audio_region()->fade_in();
5834 alist = tmp->audio_region()->fade_out();
5837 XMLNode &before = alist->get_state();
5840 tmp->audio_region()->set_fade_in_length (len);
5841 tmp->audio_region()->set_fade_in_active (true);
5843 tmp->audio_region()->set_fade_out_length (len);
5844 tmp->audio_region()->set_fade_out_active (true);
5848 begin_reversible_command (cmd);
5851 XMLNode &after = alist->get_state();
5852 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5856 commit_reversible_command ();
5861 Editor::set_fade_in_shape (FadeShape shape)
5863 RegionSelection rs = get_regions_from_selection_and_entered ();
5868 bool in_command = false;
5870 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5871 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5877 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5878 XMLNode &before = alist->get_state();
5880 tmp->audio_region()->set_fade_in_shape (shape);
5883 begin_reversible_command (_("set fade in shape"));
5886 XMLNode &after = alist->get_state();
5887 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5891 commit_reversible_command ();
5896 Editor::set_fade_out_shape (FadeShape shape)
5898 RegionSelection rs = get_regions_from_selection_and_entered ();
5903 bool in_command = false;
5905 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5906 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5912 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5913 XMLNode &before = alist->get_state();
5915 tmp->audio_region()->set_fade_out_shape (shape);
5918 begin_reversible_command (_("set fade out shape"));
5921 XMLNode &after = alist->get_state();
5922 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5926 commit_reversible_command ();
5931 Editor::set_fade_in_active (bool yn)
5933 RegionSelection rs = get_regions_from_selection_and_entered ();
5938 bool in_command = false;
5940 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5941 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5948 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5950 ar->clear_changes ();
5951 ar->set_fade_in_active (yn);
5954 begin_reversible_command (_("set fade in active"));
5957 _session->add_command (new StatefulDiffCommand (ar));
5961 commit_reversible_command ();
5966 Editor::set_fade_out_active (bool yn)
5968 RegionSelection rs = get_regions_from_selection_and_entered ();
5973 bool in_command = false;
5975 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5976 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5982 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5984 ar->clear_changes ();
5985 ar->set_fade_out_active (yn);
5988 begin_reversible_command (_("set fade out active"));
5991 _session->add_command(new StatefulDiffCommand (ar));
5995 commit_reversible_command ();
6000 Editor::toggle_region_fades (int dir)
6002 if (_ignore_region_action) {
6006 boost::shared_ptr<AudioRegion> ar;
6009 RegionSelection rs = get_regions_from_selection_and_entered ();
6015 RegionSelection::iterator i;
6016 for (i = rs.begin(); i != rs.end(); ++i) {
6017 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6019 yn = ar->fade_out_active ();
6021 yn = ar->fade_in_active ();
6027 if (i == rs.end()) {
6031 /* XXX should this undo-able? */
6032 bool in_command = false;
6034 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6035 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6038 ar->clear_changes ();
6040 if (dir == 1 || dir == 0) {
6041 ar->set_fade_in_active (!yn);
6044 if (dir == -1 || dir == 0) {
6045 ar->set_fade_out_active (!yn);
6048 begin_reversible_command (_("toggle fade active"));
6051 _session->add_command(new StatefulDiffCommand (ar));
6055 commit_reversible_command ();
6060 /** Update region fade visibility after its configuration has been changed */
6062 Editor::update_region_fade_visibility ()
6064 bool _fade_visibility = _session->config.get_show_region_fades ();
6066 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6067 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6069 if (_fade_visibility) {
6070 v->audio_view()->show_all_fades ();
6072 v->audio_view()->hide_all_fades ();
6079 Editor::set_edit_point ()
6084 if (!mouse_frame (where, ignored)) {
6090 if (selection->markers.empty()) {
6092 mouse_add_new_marker (where);
6097 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6100 loc->move_to (where);
6106 Editor::set_playhead_cursor ()
6108 if (entered_marker) {
6109 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6114 if (!mouse_frame (where, ignored)) {
6121 _session->request_locate (where, _session->transport_rolling());
6125 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
6126 cancel_time_selection();
6131 Editor::split_region ()
6133 if (_drags->active ()) {
6137 //if a range is selected, separate it
6138 if ( !selection->time.empty()) {
6139 separate_regions_between (selection->time);
6143 //if no range was selected, try to find some regions to split
6144 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6146 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6148 framepos_t where = get_preferred_edit_position ();
6154 split_regions_at (where, rs);
6158 struct EditorOrderRouteSorter {
6159 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6160 return a->order_key () < b->order_key ();
6165 Editor::select_next_route()
6167 if (selection->tracks.empty()) {
6168 selection->set (track_views.front());
6172 TimeAxisView* current = selection->tracks.front();
6176 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6177 if (*i == current) {
6179 if (i != track_views.end()) {
6182 current = (*(track_views.begin()));
6183 //selection->set (*(track_views.begin()));
6188 rui = dynamic_cast<RouteUI *>(current);
6189 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6191 selection->set(current);
6193 ensure_time_axis_view_is_visible (*current, false);
6197 Editor::select_prev_route()
6199 if (selection->tracks.empty()) {
6200 selection->set (track_views.front());
6204 TimeAxisView* current = selection->tracks.front();
6208 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6209 if (*i == current) {
6211 if (i != track_views.rend()) {
6214 current = *(track_views.rbegin());
6219 rui = dynamic_cast<RouteUI *>(current);
6220 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6222 selection->set (current);
6224 ensure_time_axis_view_is_visible (*current, false);
6228 Editor::set_loop_from_selection (bool play)
6230 if (_session == 0) {
6234 framepos_t start, end;
6235 if (!get_selection_extents ( start, end))
6238 set_loop_range (start, end, _("set loop range from selection"));
6241 _session->request_play_loop (true, true);
6246 Editor::set_loop_from_region (bool play)
6248 framepos_t start, end;
6249 if (!get_selection_extents ( start, end))
6252 set_loop_range (start, end, _("set loop range from region"));
6255 _session->request_locate (start, true);
6256 _session->request_play_loop (true);
6261 Editor::set_punch_from_selection ()
6263 if (_session == 0) {
6267 framepos_t start, end;
6268 if (!get_selection_extents ( start, end))
6271 set_punch_range (start, end, _("set punch range from selection"));
6275 Editor::set_session_extents_from_selection ()
6277 if (_session == 0) {
6281 framepos_t start, end;
6282 if (!get_selection_extents ( start, end))
6286 if ((loc = _session->locations()->session_range_location()) == 0) {
6287 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6289 XMLNode &before = loc->get_state();
6291 _session->set_session_extents ( start, end );
6293 XMLNode &after = loc->get_state();
6295 begin_reversible_command (_("set session start/end from selection"));
6297 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6299 commit_reversible_command ();
6304 Editor::set_punch_start_from_edit_point ()
6308 framepos_t start = 0;
6309 framepos_t end = max_framepos;
6311 //use the existing punch end, if any
6312 Location* tpl = transport_punch_location();
6317 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6318 start = _session->audible_frame();
6320 start = get_preferred_edit_position();
6323 //snap the selection start/end
6326 //if there's not already a sensible selection endpoint, go "forever"
6327 if ( start > end ) {
6331 set_punch_range (start, end, _("set punch start from EP"));
6337 Editor::set_punch_end_from_edit_point ()
6341 framepos_t start = 0;
6342 framepos_t end = max_framepos;
6344 //use the existing punch start, if any
6345 Location* tpl = transport_punch_location();
6347 start = tpl->start();
6350 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6351 end = _session->audible_frame();
6353 end = get_preferred_edit_position();
6356 //snap the selection start/end
6359 set_punch_range (start, end, _("set punch end from EP"));
6365 Editor::set_loop_start_from_edit_point ()
6369 framepos_t start = 0;
6370 framepos_t end = max_framepos;
6372 //use the existing loop end, if any
6373 Location* tpl = transport_loop_location();
6378 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6379 start = _session->audible_frame();
6381 start = get_preferred_edit_position();
6384 //snap the selection start/end
6387 //if there's not already a sensible selection endpoint, go "forever"
6388 if ( start > end ) {
6392 set_loop_range (start, end, _("set loop start from EP"));
6398 Editor::set_loop_end_from_edit_point ()
6402 framepos_t start = 0;
6403 framepos_t end = max_framepos;
6405 //use the existing loop start, if any
6406 Location* tpl = transport_loop_location();
6408 start = tpl->start();
6411 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6412 end = _session->audible_frame();
6414 end = get_preferred_edit_position();
6417 //snap the selection start/end
6420 set_loop_range (start, end, _("set loop end from EP"));
6425 Editor::set_punch_from_region ()
6427 framepos_t start, end;
6428 if (!get_selection_extents ( start, end))
6431 set_punch_range (start, end, _("set punch range from region"));
6435 Editor::pitch_shift_region ()
6437 RegionSelection rs = get_regions_from_selection_and_entered ();
6439 RegionSelection audio_rs;
6440 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6441 if (dynamic_cast<AudioRegionView*> (*i)) {
6442 audio_rs.push_back (*i);
6446 if (audio_rs.empty()) {
6450 pitch_shift (audio_rs, 1.2);
6454 Editor::set_tempo_from_region ()
6456 RegionSelection rs = get_regions_from_selection_and_entered ();
6458 if (!_session || rs.empty()) {
6462 RegionView* rv = rs.front();
6464 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6468 Editor::use_range_as_bar ()
6470 framepos_t start, end;
6471 if (get_edit_op_range (start, end)) {
6472 define_one_bar (start, end);
6477 Editor::define_one_bar (framepos_t start, framepos_t end)
6479 framepos_t length = end - start;
6481 const Meter& m (_session->tempo_map().meter_at (start));
6483 /* length = 1 bar */
6485 /* now we want frames per beat.
6486 we have frames per bar, and beats per bar, so ...
6489 /* XXXX METER MATH */
6491 double frames_per_beat = length / m.divisions_per_bar();
6493 /* beats per minute = */
6495 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6497 /* now decide whether to:
6499 (a) set global tempo
6500 (b) add a new tempo marker
6504 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6506 bool do_global = false;
6508 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6510 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6511 at the start, or create a new marker
6514 vector<string> options;
6515 options.push_back (_("Cancel"));
6516 options.push_back (_("Add new marker"));
6517 options.push_back (_("Set global tempo"));
6520 _("Define one bar"),
6521 _("Do you want to set the global tempo or add a new tempo marker?"),
6525 c.set_default_response (2);
6541 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6542 if the marker is at the region starter, change it, otherwise add
6547 begin_reversible_command (_("set tempo from region"));
6548 XMLNode& before (_session->tempo_map().get_state());
6551 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6552 } else if (t.frame() == start) {
6553 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6555 Timecode::BBT_Time bbt;
6556 _session->tempo_map().bbt_time (start, bbt);
6557 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6560 XMLNode& after (_session->tempo_map().get_state());
6562 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6563 commit_reversible_command ();
6567 Editor::split_region_at_transients ()
6569 AnalysisFeatureList positions;
6571 RegionSelection rs = get_regions_from_selection_and_entered ();
6573 if (!_session || rs.empty()) {
6577 begin_reversible_command (_("split regions"));
6579 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6581 RegionSelection::iterator tmp;
6586 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6588 if (ar && (ar->get_transients (positions) == 0)) {
6589 split_region_at_points ((*i)->region(), positions, true);
6596 commit_reversible_command ();
6601 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6603 bool use_rhythmic_rodent = false;
6605 boost::shared_ptr<Playlist> pl = r->playlist();
6607 list<boost::shared_ptr<Region> > new_regions;
6613 if (positions.empty()) {
6618 if (positions.size() > 20 && can_ferret) {
6619 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);
6620 MessageDialog msg (msgstr,
6623 Gtk::BUTTONS_OK_CANCEL);
6626 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6627 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6629 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6632 msg.set_title (_("Excessive split?"));
6635 int response = msg.run();
6641 case RESPONSE_APPLY:
6642 use_rhythmic_rodent = true;
6649 if (use_rhythmic_rodent) {
6650 show_rhythm_ferret ();
6654 AnalysisFeatureList::const_iterator x;
6656 pl->clear_changes ();
6657 pl->clear_owned_changes ();
6659 x = positions.begin();
6661 if (x == positions.end()) {
6666 pl->remove_region (r);
6670 while (x != positions.end()) {
6672 /* deal with positons that are out of scope of present region bounds */
6673 if (*x <= 0 || *x > r->length()) {
6678 /* file start = original start + how far we from the initial position ?
6681 framepos_t file_start = r->start() + pos;
6683 /* length = next position - current position
6686 framepos_t len = (*x) - pos;
6688 /* XXX we do we really want to allow even single-sample regions?
6689 shouldn't we have some kind of lower limit on region size?
6698 if (RegionFactory::region_name (new_name, r->name())) {
6702 /* do NOT announce new regions 1 by one, just wait till they are all done */
6706 plist.add (ARDOUR::Properties::start, file_start);
6707 plist.add (ARDOUR::Properties::length, len);
6708 plist.add (ARDOUR::Properties::name, new_name);
6709 plist.add (ARDOUR::Properties::layer, 0);
6711 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6712 /* because we set annouce to false, manually add the new region to the
6715 RegionFactory::map_add (nr);
6717 pl->add_region (nr, r->position() + pos);
6720 new_regions.push_front(nr);
6729 RegionFactory::region_name (new_name, r->name());
6731 /* Add the final region */
6734 plist.add (ARDOUR::Properties::start, r->start() + pos);
6735 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6736 plist.add (ARDOUR::Properties::name, new_name);
6737 plist.add (ARDOUR::Properties::layer, 0);
6739 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6740 /* because we set annouce to false, manually add the new region to the
6743 RegionFactory::map_add (nr);
6744 pl->add_region (nr, r->position() + pos);
6747 new_regions.push_front(nr);
6752 /* We might have removed regions, which alters other regions' layering_index,
6753 so we need to do a recursive diff here.
6755 vector<Command*> cmds;
6757 _session->add_commands (cmds);
6759 _session->add_command (new StatefulDiffCommand (pl));
6763 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6764 set_selected_regionview_from_region_list ((*i), Selection::Add);
6770 Editor::place_transient()
6776 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6782 framepos_t where = get_preferred_edit_position();
6784 begin_reversible_command (_("place transient"));
6786 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6787 framepos_t position = (*r)->region()->position();
6788 (*r)->region()->add_transient(where - position);
6791 commit_reversible_command ();
6795 Editor::remove_transient(ArdourCanvas::Item* item)
6801 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6804 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6805 _arv->remove_transient (*(float*) _line->get_data ("position"));
6809 Editor::snap_regions_to_grid ()
6811 list <boost::shared_ptr<Playlist > > used_playlists;
6813 RegionSelection rs = get_regions_from_selection_and_entered ();
6815 if (!_session || rs.empty()) {
6819 begin_reversible_command (_("snap regions to grid"));
6821 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6823 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6825 if (!pl->frozen()) {
6826 /* we haven't seen this playlist before */
6828 /* remember used playlists so we can thaw them later */
6829 used_playlists.push_back(pl);
6833 framepos_t start_frame = (*r)->region()->first_frame ();
6834 snap_to (start_frame);
6835 (*r)->region()->set_position (start_frame);
6838 while (used_playlists.size() > 0) {
6839 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6841 used_playlists.pop_front();
6844 commit_reversible_command ();
6848 Editor::close_region_gaps ()
6850 list <boost::shared_ptr<Playlist > > used_playlists;
6852 RegionSelection rs = get_regions_from_selection_and_entered ();
6854 if (!_session || rs.empty()) {
6858 Dialog dialog (_("Close Region Gaps"));
6861 table.set_spacings (12);
6862 table.set_border_width (12);
6863 Label* l = manage (left_aligned_label (_("Crossfade length")));
6864 table.attach (*l, 0, 1, 0, 1);
6866 SpinButton spin_crossfade (1, 0);
6867 spin_crossfade.set_range (0, 15);
6868 spin_crossfade.set_increments (1, 1);
6869 spin_crossfade.set_value (5);
6870 table.attach (spin_crossfade, 1, 2, 0, 1);
6872 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6874 l = manage (left_aligned_label (_("Pull-back length")));
6875 table.attach (*l, 0, 1, 1, 2);
6877 SpinButton spin_pullback (1, 0);
6878 spin_pullback.set_range (0, 100);
6879 spin_pullback.set_increments (1, 1);
6880 spin_pullback.set_value(30);
6881 table.attach (spin_pullback, 1, 2, 1, 2);
6883 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6885 dialog.get_vbox()->pack_start (table);
6886 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6887 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6890 if (dialog.run () == RESPONSE_CANCEL) {
6894 framepos_t crossfade_len = spin_crossfade.get_value();
6895 framepos_t pull_back_frames = spin_pullback.get_value();
6897 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6898 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6900 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6902 begin_reversible_command (_("close region gaps"));
6905 boost::shared_ptr<Region> last_region;
6907 rs.sort_by_position_and_track();
6909 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6911 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6913 if (!pl->frozen()) {
6914 /* we haven't seen this playlist before */
6916 /* remember used playlists so we can thaw them later */
6917 used_playlists.push_back(pl);
6921 framepos_t position = (*r)->region()->position();
6923 if (idx == 0 || position < last_region->position()){
6924 last_region = (*r)->region();
6929 (*r)->region()->trim_front( (position - pull_back_frames));
6930 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6932 last_region = (*r)->region();
6937 while (used_playlists.size() > 0) {
6938 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6940 used_playlists.pop_front();
6943 commit_reversible_command ();
6947 Editor::tab_to_transient (bool forward)
6949 AnalysisFeatureList positions;
6951 RegionSelection rs = get_regions_from_selection_and_entered ();
6957 framepos_t pos = _session->audible_frame ();
6959 if (!selection->tracks.empty()) {
6961 /* don't waste time searching for transients in duplicate playlists.
6964 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6966 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6968 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6971 boost::shared_ptr<Track> tr = rtv->track();
6973 boost::shared_ptr<Playlist> pl = tr->playlist ();
6975 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6978 positions.push_back (result);
6991 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6992 (*r)->region()->get_transients (positions);
6996 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6999 AnalysisFeatureList::iterator x;
7001 for (x = positions.begin(); x != positions.end(); ++x) {
7007 if (x != positions.end ()) {
7008 _session->request_locate (*x);
7012 AnalysisFeatureList::reverse_iterator x;
7014 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7020 if (x != positions.rend ()) {
7021 _session->request_locate (*x);
7027 Editor::playhead_forward_to_grid ()
7033 framepos_t pos = playhead_cursor->current_frame ();
7034 if (pos < max_framepos - 1) {
7036 snap_to_internal (pos, RoundUpAlways, false);
7037 _session->request_locate (pos);
7043 Editor::playhead_backward_to_grid ()
7049 framepos_t pos = playhead_cursor->current_frame ();
7052 snap_to_internal (pos, RoundDownAlways, false);
7053 _session->request_locate (pos);
7058 Editor::set_track_height (Height h)
7060 TrackSelection& ts (selection->tracks);
7062 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7063 (*x)->set_height_enum (h);
7068 Editor::toggle_tracks_active ()
7070 TrackSelection& ts (selection->tracks);
7072 bool target = false;
7078 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7079 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7083 target = !rtv->_route->active();
7086 rtv->_route->set_active (target, this);
7092 Editor::remove_tracks ()
7094 /* this will delete GUI objects that may be the subject of an event
7095 handler in which this method is called. Defer actual deletion to the
7096 next idle callback, when all event handling is finished.
7098 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7102 Editor::idle_remove_tracks ()
7105 return false; /* do not call again */
7109 Editor::_remove_tracks ()
7111 TrackSelection& ts (selection->tracks);
7117 vector<string> choices;
7121 const char* trackstr;
7123 vector<boost::shared_ptr<Route> > routes;
7124 bool special_bus = false;
7126 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7127 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7131 if (rtv->is_track()) {
7136 routes.push_back (rtv->_route);
7138 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7143 if (special_bus && !Config->get_allow_special_bus_removal()) {
7144 MessageDialog msg (_("That would be bad news ...."),
7148 msg.set_secondary_text (string_compose (_(
7149 "Removing the master or monitor bus is such a bad idea\n\
7150 that %1 is not going to allow it.\n\
7152 If you really want to do this sort of thing\n\
7153 edit your ardour.rc file to set the\n\
7154 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7161 if (ntracks + nbusses == 0) {
7165 trackstr = P_("track", "tracks", ntracks);
7166 busstr = P_("bus", "busses", nbusses);
7170 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7171 "(You may also lose the playlists associated with the %2)\n\n"
7172 "This action cannot be undone, and the session file will be overwritten!"),
7173 ntracks, trackstr, nbusses, busstr);
7175 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7176 "(You may also lose the playlists associated with the %2)\n\n"
7177 "This action cannot be undone, and the session file will be overwritten!"),
7180 } else if (nbusses) {
7181 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7182 "This action cannot be undone, and the session file will be overwritten"),
7186 choices.push_back (_("No, do nothing."));
7187 if (ntracks + nbusses > 1) {
7188 choices.push_back (_("Yes, remove them."));
7190 choices.push_back (_("Yes, remove it."));
7195 title = string_compose (_("Remove %1"), trackstr);
7197 title = string_compose (_("Remove %1"), busstr);
7200 Choice prompter (title, prompt, choices);
7202 if (prompter.run () != 1) {
7207 Session::StateProtector sp (_session);
7208 DisplaySuspender ds;
7209 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7210 _session->remove_route (*x);
7216 Editor::do_insert_time ()
7218 if (selection->tracks.empty()) {
7222 InsertRemoveTimeDialog d (*this);
7223 int response = d.run ();
7225 if (response != RESPONSE_OK) {
7229 if (d.distance() == 0) {
7233 InsertTimeOption opt = d.intersected_region_action ();
7236 get_preferred_edit_position(),
7242 d.move_glued_markers(),
7243 d.move_locked_markers(),
7249 Editor::insert_time (
7250 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7251 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7255 if (Config->get_edit_mode() == Lock) {
7258 bool in_command = false;
7260 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7262 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7266 /* don't operate on any playlist more than once, which could
7267 * happen if "all playlists" is enabled, but there is more
7268 * than 1 track using playlists "from" a given track.
7271 set<boost::shared_ptr<Playlist> > pl;
7273 if (all_playlists) {
7274 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7275 if (rtav && rtav->track ()) {
7276 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7277 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7282 if ((*x)->playlist ()) {
7283 pl.insert ((*x)->playlist ());
7287 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7289 (*i)->clear_changes ();
7290 (*i)->clear_owned_changes ();
7292 if (opt == SplitIntersected) {
7296 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7299 begin_reversible_command (_("insert time"));
7302 vector<Command*> cmds;
7304 _session->add_commands (cmds);
7306 _session->add_command (new StatefulDiffCommand (*i));
7310 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7313 begin_reversible_command (_("insert time"));
7316 rtav->route ()->shift (pos, frames);
7323 XMLNode& before (_session->locations()->get_state());
7324 Locations::LocationList copy (_session->locations()->list());
7326 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7328 Locations::LocationList::const_iterator tmp;
7330 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7331 bool const was_locked = (*i)->locked ();
7332 if (locked_markers_too) {
7336 if ((*i)->start() >= pos) {
7337 // move end first, in case we're moving by more than the length of the range
7338 if (!(*i)->is_mark()) {
7339 (*i)->set_end ((*i)->end() + frames);
7341 (*i)->set_start ((*i)->start() + frames);
7353 begin_reversible_command (_("insert time"));
7356 XMLNode& after (_session->locations()->get_state());
7357 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7363 begin_reversible_command (_("insert time"));
7366 XMLNode& before (_session->tempo_map().get_state());
7367 _session->tempo_map().insert_time (pos, frames);
7368 XMLNode& after (_session->tempo_map().get_state());
7369 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7373 commit_reversible_command ();
7378 Editor::do_remove_time ()
7380 if (selection->tracks.empty()) {
7384 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7385 InsertRemoveTimeDialog d (*this, true);
7387 int response = d.run ();
7389 if (response != RESPONSE_OK) {
7393 framecnt_t distance = d.distance();
7395 if (distance == 0) {
7405 d.move_glued_markers(),
7406 d.move_locked_markers(),
7412 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7413 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7415 if (Config->get_edit_mode() == Lock) {
7416 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7419 bool in_command = false;
7421 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7423 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7427 XMLNode &before = pl->get_state();
7429 std::list<AudioRange> rl;
7430 AudioRange ar(pos, pos+frames, 0);
7433 pl->shift (pos, -frames, true, ignore_music_glue);
7436 begin_reversible_command (_("cut time"));
7439 XMLNode &after = pl->get_state();
7441 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7445 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7448 begin_reversible_command (_("cut time"));
7451 rtav->route ()->shift (pos, -frames);
7455 std::list<Location*> loc_kill_list;
7460 XMLNode& before (_session->locations()->get_state());
7461 Locations::LocationList copy (_session->locations()->list());
7463 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7464 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7466 bool const was_locked = (*i)->locked ();
7467 if (locked_markers_too) {
7471 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7472 if ((*i)->end() >= pos
7473 && (*i)->end() < pos+frames
7474 && (*i)->start() >= pos
7475 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7477 loc_kill_list.push_back(*i);
7478 } else { // only start or end is included, try to do the right thing
7479 // move start before moving end, to avoid trying to move the end to before the start
7480 // if we're removing more time than the length of the range
7481 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7482 // start is within cut
7483 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7485 } else if ((*i)->start() >= pos+frames) {
7486 // start (and thus entire range) lies beyond end of cut
7487 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7490 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7491 // end is inside cut
7492 (*i)->set_end (pos); // bring the end to the cut
7494 } else if ((*i)->end() >= pos+frames) {
7495 // end is beyond end of cut
7496 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7501 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7502 loc_kill_list.push_back(*i);
7504 } else if ((*i)->start() >= pos) {
7505 (*i)->set_start ((*i)->start() -frames);
7515 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7516 _session->locations()->remove( *i );
7521 begin_reversible_command (_("cut time"));
7524 XMLNode& after (_session->locations()->get_state());
7525 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7530 XMLNode& before (_session->tempo_map().get_state());
7532 if (_session->tempo_map().remove_time (pos, frames) ) {
7534 begin_reversible_command (_("remove time"));
7537 XMLNode& after (_session->tempo_map().get_state());
7538 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7543 commit_reversible_command ();
7548 Editor::fit_selection ()
7550 if (!selection->tracks.empty()) {
7551 fit_tracks (selection->tracks);
7555 /* no selected tracks - use tracks with selected regions */
7557 if (!selection->regions.empty()) {
7558 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7559 tvl.push_back (&(*r)->get_time_axis_view ());
7565 } else if (internal_editing()) {
7566 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7569 if (entered_track) {
7570 tvl.push_back (entered_track);
7579 Editor::fit_tracks (TrackViewList & tracks)
7581 if (tracks.empty()) {
7585 uint32_t child_heights = 0;
7586 int visible_tracks = 0;
7588 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7590 if (!(*t)->marked_for_display()) {
7594 child_heights += (*t)->effective_height() - (*t)->current_height();
7598 /* compute the per-track height from:
7600 total canvas visible height -
7601 height that will be taken by visible children of selected
7602 tracks - height of the ruler/hscroll area
7604 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7605 double first_y_pos = DBL_MAX;
7607 if (h < TimeAxisView::preset_height (HeightSmall)) {
7608 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7609 /* too small to be displayed */
7613 undo_visual_stack.push_back (current_visual_state (true));
7614 PBD::Unwinder<bool> nsv (no_save_visual, true);
7616 /* build a list of all tracks, including children */
7619 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7621 TimeAxisView::Children c = (*i)->get_child_list ();
7622 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7623 all.push_back (j->get());
7628 // find selection range.
7629 // if someone knows how to user TrackViewList::iterator for this
7631 int selected_top = -1;
7632 int selected_bottom = -1;
7634 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7635 if ((*t)->marked_for_display ()) {
7636 if (tracks.contains(*t)) {
7637 if (selected_top == -1) {
7640 selected_bottom = i;
7646 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7647 if ((*t)->marked_for_display ()) {
7648 if (tracks.contains(*t)) {
7649 (*t)->set_height (h);
7650 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7652 if (i > selected_top && i < selected_bottom) {
7653 hide_track_in_display (*t);
7660 set the controls_layout height now, because waiting for its size
7661 request signal handler will cause the vertical adjustment setting to fail
7664 controls_layout.property_height () = _full_canvas_height;
7665 vertical_adjustment.set_value (first_y_pos);
7667 redo_visual_stack.push_back (current_visual_state (true));
7669 visible_tracks_selector.set_text (_("Sel"));
7673 Editor::save_visual_state (uint32_t n)
7675 while (visual_states.size() <= n) {
7676 visual_states.push_back (0);
7679 if (visual_states[n] != 0) {
7680 delete visual_states[n];
7683 visual_states[n] = current_visual_state (true);
7688 Editor::goto_visual_state (uint32_t n)
7690 if (visual_states.size() <= n) {
7694 if (visual_states[n] == 0) {
7698 use_visual_state (*visual_states[n]);
7702 Editor::start_visual_state_op (uint32_t n)
7704 save_visual_state (n);
7706 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7708 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7709 pup->set_text (buf);
7714 Editor::cancel_visual_state_op (uint32_t n)
7716 goto_visual_state (n);
7720 Editor::toggle_region_mute ()
7722 if (_ignore_region_action) {
7726 RegionSelection rs = get_regions_from_selection_and_entered ();
7732 if (rs.size() > 1) {
7733 begin_reversible_command (_("mute regions"));
7735 begin_reversible_command (_("mute region"));
7738 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7740 (*i)->region()->playlist()->clear_changes ();
7741 (*i)->region()->set_muted (!(*i)->region()->muted ());
7742 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7746 commit_reversible_command ();
7750 Editor::combine_regions ()
7752 /* foreach track with selected regions, take all selected regions
7753 and join them into a new region containing the subregions (as a
7757 typedef set<RouteTimeAxisView*> RTVS;
7760 if (selection->regions.empty()) {
7764 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7765 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7768 tracks.insert (rtv);
7772 begin_reversible_command (_("combine regions"));
7774 vector<RegionView*> new_selection;
7776 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7779 if ((rv = (*i)->combine_regions ()) != 0) {
7780 new_selection.push_back (rv);
7784 selection->clear_regions ();
7785 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7786 selection->add (*i);
7789 commit_reversible_command ();
7793 Editor::uncombine_regions ()
7795 typedef set<RouteTimeAxisView*> RTVS;
7798 if (selection->regions.empty()) {
7802 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7803 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7806 tracks.insert (rtv);
7810 begin_reversible_command (_("uncombine regions"));
7812 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7813 (*i)->uncombine_regions ();
7816 commit_reversible_command ();
7820 Editor::toggle_midi_input_active (bool flip_others)
7823 boost::shared_ptr<RouteList> rl (new RouteList);
7825 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7826 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7832 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7835 rl->push_back (rtav->route());
7836 onoff = !mt->input_active();
7840 _session->set_exclusive_input_active (rl, onoff, flip_others);
7847 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7849 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7850 lock_dialog->get_vbox()->pack_start (*padlock);
7852 ArdourButton* b = manage (new ArdourButton);
7853 b->set_name ("lock button");
7854 b->set_text (_("Click to unlock"));
7855 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7856 lock_dialog->get_vbox()->pack_start (*b);
7858 lock_dialog->get_vbox()->show_all ();
7859 lock_dialog->set_size_request (200, 200);
7862 delete _main_menu_disabler;
7863 _main_menu_disabler = new MainMenuDisabler;
7865 lock_dialog->present ();
7871 lock_dialog->hide ();
7873 delete _main_menu_disabler;
7874 _main_menu_disabler = 0;
7876 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7877 start_lock_event_timing ();
7882 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7884 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7888 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7890 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7891 Gtkmm2ext::UI::instance()->flush_pending ();
7895 Editor::bring_all_sources_into_session ()
7902 ArdourDialog w (_("Moving embedded files into session folder"));
7903 w.get_vbox()->pack_start (msg);
7906 /* flush all pending GUI events because we're about to start copying
7910 Gtkmm2ext::UI::instance()->flush_pending ();
7914 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));