2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/boost_debug.h"
46 #include "ardour/dB.h"
47 #include "ardour/location.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/operations.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/profile.h"
53 #include "ardour/quantize.h"
54 #include "ardour/legatize.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/reverse.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/strip_silence.h"
60 #include "ardour/transient_detector.h"
61 #include "ardour/transpose.h"
63 #include "canvas/canvas.h"
66 #include "audio_region_view.h"
67 #include "audio_streamview.h"
68 #include "audio_time_axis.h"
69 #include "automation_region_view.h"
70 #include "automation_time_axis.h"
71 #include "control_point.h"
75 #include "editor_cursors.h"
76 #include "editor_drag.h"
77 #include "editor_regions.h"
78 #include "editor_routes.h"
79 #include "gui_thread.h"
80 #include "insert_remove_time_dialog.h"
81 #include "interthread_progress_window.h"
82 #include "item_counts.h"
84 #include "midi_region_view.h"
86 #include "mixer_strip.h"
87 #include "mouse_cursors.h"
88 #include "normalize_dialog.h"
90 #include "paste_context.h"
91 #include "patch_change_dialog.h"
92 #include "quantize_dialog.h"
93 #include "region_gain_line.h"
94 #include "rgb_macros.h"
95 #include "route_time_axis.h"
96 #include "selection.h"
97 #include "selection_templates.h"
98 #include "streamview.h"
99 #include "strip_silence_dialog.h"
100 #include "time_axis_view.h"
102 #include "transpose_dialog.h"
103 #include "transform_dialog.h"
104 #include "ui_config.h"
106 #include "pbd/i18n.h"
109 using namespace ARDOUR;
112 using namespace Gtkmm2ext;
113 using namespace Editing;
114 using Gtkmm2ext::Keyboard;
116 /***********************************************************************
118 ***********************************************************************/
121 Editor::undo (uint32_t n)
123 if (_session && _session->actively_recording()) {
124 /* no undo allowed while recording. Session will check also,
125 but we don't even want to get to that.
130 if (_drags->active ()) {
136 if (_session->undo_depth() == 0) {
137 undo_action->set_sensitive(false);
139 redo_action->set_sensitive(true);
140 begin_selection_op_history ();
145 Editor::redo (uint32_t n)
147 if (_session && _session->actively_recording()) {
148 /* no redo allowed while recording. Session will check also,
149 but we don't even want to get to that.
154 if (_drags->active ()) {
160 if (_session->redo_depth() == 0) {
161 redo_action->set_sensitive(false);
163 undo_action->set_sensitive(true);
164 begin_selection_op_history ();
169 Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int32_t sub_num)
173 RegionSelection pre_selected_regions = selection->regions;
174 bool working_on_selection = !pre_selected_regions.empty();
176 list<boost::shared_ptr<Playlist> > used_playlists;
177 list<RouteTimeAxisView*> used_trackviews;
179 if (regions.empty()) {
183 begin_reversible_command (_("split"));
185 // if splitting a single region, and snap-to is using
186 // region boundaries, don't pay attention to them
188 if (regions.size() == 1) {
189 switch (_snap_type) {
190 case SnapToRegionStart:
191 case SnapToRegionSync:
192 case SnapToRegionEnd:
201 EditorFreeze(); /* Emit Signal */
204 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
206 RegionSelection::iterator tmp;
208 /* XXX this test needs to be more complicated, to make sure we really
209 have something to split.
212 if (!(*a)->region()->covers (where)) {
220 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
228 /* we haven't seen this playlist before */
230 /* remember used playlists so we can thaw them later */
231 used_playlists.push_back(pl);
233 TimeAxisView& tv = (*a)->get_time_axis_view();
234 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
236 used_trackviews.push_back (rtv);
243 pl->clear_changes ();
244 pl->split_region ((*a)->region(), where, sub_num);
245 _session->add_command (new StatefulDiffCommand (pl));
251 latest_regionviews.clear ();
253 vector<sigc::connection> region_added_connections;
255 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
256 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
259 while (used_playlists.size() > 0) {
260 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
262 used_playlists.pop_front();
265 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
270 EditorThaw(); /* Emit Signal */
273 if (working_on_selection) {
274 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
276 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
277 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
278 /* There are three classes of regions that we might want selected after
279 splitting selected regions:
280 - regions selected before the split operation, and unaffected by it
281 - newly-created regions before the split
282 - newly-created regions after the split
285 if (rsas & Existing) {
286 // region selections that existed before the split.
287 selection->add ( pre_selected_regions );
290 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
291 if ((*ri)->region()->position() < where) {
292 // new regions created before the split
293 if (rsas & NewlyCreatedLeft) {
294 selection->add (*ri);
297 // new regions created after the split
298 if (rsas & NewlyCreatedRight) {
299 selection->add (*ri);
303 _ignore_follow_edits = false;
305 _ignore_follow_edits = true;
306 if( working_on_selection ) {
307 selection->add (latest_regionviews); //these are the new regions created after the split
309 _ignore_follow_edits = false;
312 commit_reversible_command ();
315 /** Move one extreme of the current range selection. If more than one range is selected,
316 * the start of the earliest range or the end of the latest range is moved.
318 * @param move_end true to move the end of the current range selection, false to move
320 * @param next true to move the extreme to the next region boundary, false to move to
324 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
326 if (selection->time.start() == selection->time.end_frame()) {
330 framepos_t start = selection->time.start ();
331 framepos_t end = selection->time.end_frame ();
333 /* the position of the thing we may move */
334 framepos_t pos = move_end ? end : start;
335 int dir = next ? 1 : -1;
337 /* so we don't find the current region again */
338 if (dir > 0 || pos > 0) {
342 framepos_t const target = get_region_boundary (pos, dir, true, false);
357 begin_reversible_selection_op (_("alter selection"));
358 selection->set_preserving_all_ranges (start, end);
359 commit_reversible_selection_op ();
363 Editor::nudge_forward_release (GdkEventButton* ev)
365 if (ev->state & Keyboard::PrimaryModifier) {
366 nudge_forward (false, true);
368 nudge_forward (false, false);
374 Editor::nudge_backward_release (GdkEventButton* ev)
376 if (ev->state & Keyboard::PrimaryModifier) {
377 nudge_backward (false, true);
379 nudge_backward (false, false);
386 Editor::nudge_forward (bool next, bool force_playhead)
389 framepos_t next_distance;
395 RegionSelection rs = get_regions_from_selection_and_entered ();
397 if (!force_playhead && !rs.empty()) {
399 begin_reversible_command (_("nudge regions forward"));
401 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
402 boost::shared_ptr<Region> r ((*i)->region());
404 distance = get_nudge_distance (r->position(), next_distance);
407 distance = next_distance;
411 r->set_position (r->position() + distance);
412 _session->add_command (new StatefulDiffCommand (r));
415 commit_reversible_command ();
418 } else if (!force_playhead && !selection->markers.empty()) {
421 bool in_command = false;
423 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
425 Location* loc = find_location_from_marker ((*i), is_start);
429 XMLNode& before (loc->get_state());
432 distance = get_nudge_distance (loc->start(), next_distance);
434 distance = next_distance;
436 if (max_framepos - distance > loc->start() + loc->length()) {
437 loc->set_start (loc->start() + distance);
439 loc->set_start (max_framepos - loc->length());
442 distance = get_nudge_distance (loc->end(), next_distance);
444 distance = next_distance;
446 if (max_framepos - distance > loc->end()) {
447 loc->set_end (loc->end() + distance);
449 loc->set_end (max_framepos);
451 if (loc->is_session_range()) {
452 _session->set_end_is_free (false);
456 begin_reversible_command (_("nudge location forward"));
459 XMLNode& after (loc->get_state());
460 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
465 commit_reversible_command ();
468 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
469 _session->request_locate (playhead_cursor->current_frame () + distance);
474 Editor::nudge_backward (bool next, bool force_playhead)
477 framepos_t next_distance;
483 RegionSelection rs = get_regions_from_selection_and_entered ();
485 if (!force_playhead && !rs.empty()) {
487 begin_reversible_command (_("nudge regions backward"));
489 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
490 boost::shared_ptr<Region> r ((*i)->region());
492 distance = get_nudge_distance (r->position(), next_distance);
495 distance = next_distance;
500 if (r->position() > distance) {
501 r->set_position (r->position() - distance);
505 _session->add_command (new StatefulDiffCommand (r));
508 commit_reversible_command ();
510 } else if (!force_playhead && !selection->markers.empty()) {
513 bool in_command = false;
515 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
517 Location* loc = find_location_from_marker ((*i), is_start);
521 XMLNode& before (loc->get_state());
524 distance = get_nudge_distance (loc->start(), next_distance);
526 distance = next_distance;
528 if (distance < loc->start()) {
529 loc->set_start (loc->start() - distance);
534 distance = get_nudge_distance (loc->end(), next_distance);
537 distance = next_distance;
540 if (distance < loc->end() - loc->length()) {
541 loc->set_end (loc->end() - distance);
543 loc->set_end (loc->length());
545 if (loc->is_session_range()) {
546 _session->set_end_is_free (false);
550 begin_reversible_command (_("nudge location forward"));
553 XMLNode& after (loc->get_state());
554 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
558 commit_reversible_command ();
563 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
565 if (playhead_cursor->current_frame () > distance) {
566 _session->request_locate (playhead_cursor->current_frame () - distance);
568 _session->goto_start();
574 Editor::nudge_forward_capture_offset ()
576 RegionSelection rs = get_regions_from_selection_and_entered ();
578 if (!_session || rs.empty()) {
582 begin_reversible_command (_("nudge forward"));
584 framepos_t const distance = _session->worst_output_latency();
586 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
587 boost::shared_ptr<Region> r ((*i)->region());
590 r->set_position (r->position() + distance);
591 _session->add_command(new StatefulDiffCommand (r));
594 commit_reversible_command ();
598 Editor::nudge_backward_capture_offset ()
600 RegionSelection rs = get_regions_from_selection_and_entered ();
602 if (!_session || rs.empty()) {
606 begin_reversible_command (_("nudge backward"));
608 framepos_t const distance = _session->worst_output_latency();
610 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
611 boost::shared_ptr<Region> r ((*i)->region());
615 if (r->position() > distance) {
616 r->set_position (r->position() - distance);
620 _session->add_command(new StatefulDiffCommand (r));
623 commit_reversible_command ();
626 struct RegionSelectionPositionSorter {
627 bool operator() (RegionView* a, RegionView* b) {
628 return a->region()->position() < b->region()->position();
633 Editor::sequence_regions ()
636 framepos_t r_end_prev;
644 RegionSelection rs = get_regions_from_selection_and_entered ();
645 rs.sort(RegionSelectionPositionSorter());
649 bool in_command = false;
651 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
652 boost::shared_ptr<Region> r ((*i)->region());
660 if(r->position_locked())
667 r->set_position(r_end_prev);
671 begin_reversible_command (_("sequence regions"));
674 _session->add_command (new StatefulDiffCommand (r));
676 r_end=r->position() + r->length();
682 commit_reversible_command ();
691 Editor::move_to_start ()
693 _session->goto_start ();
697 Editor::move_to_end ()
700 _session->request_locate (_session->current_end_frame());
704 Editor::build_region_boundary_cache ()
707 vector<RegionPoint> interesting_points;
708 boost::shared_ptr<Region> r;
709 TrackViewList tracks;
712 region_boundary_cache.clear ();
718 switch (_snap_type) {
719 case SnapToRegionStart:
720 interesting_points.push_back (Start);
722 case SnapToRegionEnd:
723 interesting_points.push_back (End);
725 case SnapToRegionSync:
726 interesting_points.push_back (SyncPoint);
728 case SnapToRegionBoundary:
729 interesting_points.push_back (Start);
730 interesting_points.push_back (End);
733 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
734 abort(); /*NOTREACHED*/
738 TimeAxisView *ontrack = 0;
741 if (!selection->tracks.empty()) {
742 tlist = selection->tracks.filter_to_unique_playlists ();
744 tlist = track_views.filter_to_unique_playlists ();
747 while (pos < _session->current_end_frame() && !at_end) {
750 framepos_t lpos = max_framepos;
752 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
754 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
755 if (*p == interesting_points.back()) {
758 /* move to next point type */
764 rpos = r->first_frame();
768 rpos = r->last_frame();
772 rpos = r->sync_position ();
780 RouteTimeAxisView *rtav;
782 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
783 if (rtav->track() != 0) {
784 speed = rtav->track()->speed();
788 rpos = track_frame_to_session_frame (rpos, speed);
794 /* prevent duplicates, but we don't use set<> because we want to be able
798 vector<framepos_t>::iterator ri;
800 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
806 if (ri == region_boundary_cache.end()) {
807 region_boundary_cache.push_back (rpos);
814 /* finally sort to be sure that the order is correct */
816 sort (region_boundary_cache.begin(), region_boundary_cache.end());
819 boost::shared_ptr<Region>
820 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
822 TrackViewList::iterator i;
823 framepos_t closest = max_framepos;
824 boost::shared_ptr<Region> ret;
828 framepos_t track_frame;
829 RouteTimeAxisView *rtav;
831 for (i = tracks.begin(); i != tracks.end(); ++i) {
834 boost::shared_ptr<Region> r;
837 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
838 if (rtav->track()!=0)
839 track_speed = rtav->track()->speed();
842 track_frame = session_frame_to_track_frame(frame, track_speed);
844 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
850 rpos = r->first_frame ();
854 rpos = r->last_frame ();
858 rpos = r->sync_position ();
862 // rpos is a "track frame", converting it to "_session frame"
863 rpos = track_frame_to_session_frame(rpos, track_speed);
866 distance = rpos - frame;
868 distance = frame - rpos;
871 if (distance < closest) {
883 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
885 framecnt_t distance = max_framepos;
886 framepos_t current_nearest = -1;
888 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
889 framepos_t contender;
892 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
898 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
902 d = ::llabs (pos - contender);
905 current_nearest = contender;
910 return current_nearest;
914 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
919 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
921 if (!selection->tracks.empty()) {
923 target = find_next_region_boundary (pos, dir, selection->tracks);
927 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
928 get_onscreen_tracks (tvl);
929 target = find_next_region_boundary (pos, dir, tvl);
931 target = find_next_region_boundary (pos, dir, track_views);
937 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
938 get_onscreen_tracks (tvl);
939 target = find_next_region_boundary (pos, dir, tvl);
941 target = find_next_region_boundary (pos, dir, track_views);
949 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
951 framepos_t pos = playhead_cursor->current_frame ();
958 // so we don't find the current region again..
959 if (dir > 0 || pos > 0) {
963 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
967 _session->request_locate (target);
971 Editor::cursor_to_next_region_boundary (bool with_selection)
973 cursor_to_region_boundary (with_selection, 1);
977 Editor::cursor_to_previous_region_boundary (bool with_selection)
979 cursor_to_region_boundary (with_selection, -1);
983 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
985 boost::shared_ptr<Region> r;
986 framepos_t pos = cursor->current_frame ();
992 TimeAxisView *ontrack = 0;
994 // so we don't find the current region again..
998 if (!selection->tracks.empty()) {
1000 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1002 } else if (clicked_axisview) {
1005 t.push_back (clicked_axisview);
1007 r = find_next_region (pos, point, dir, t, &ontrack);
1011 r = find_next_region (pos, point, dir, track_views, &ontrack);
1020 pos = r->first_frame ();
1024 pos = r->last_frame ();
1028 pos = r->sync_position ();
1033 RouteTimeAxisView *rtav;
1035 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1036 if (rtav->track() != 0) {
1037 speed = rtav->track()->speed();
1041 pos = track_frame_to_session_frame(pos, speed);
1043 if (cursor == playhead_cursor) {
1044 _session->request_locate (pos);
1046 cursor->set_position (pos);
1051 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1053 cursor_to_region_point (cursor, point, 1);
1057 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1059 cursor_to_region_point (cursor, point, -1);
1063 Editor::cursor_to_selection_start (EditorCursor *cursor)
1067 switch (mouse_mode) {
1069 if (!selection->regions.empty()) {
1070 pos = selection->regions.start();
1075 if (!selection->time.empty()) {
1076 pos = selection->time.start ();
1084 if (cursor == playhead_cursor) {
1085 _session->request_locate (pos);
1087 cursor->set_position (pos);
1092 Editor::cursor_to_selection_end (EditorCursor *cursor)
1096 switch (mouse_mode) {
1098 if (!selection->regions.empty()) {
1099 pos = selection->regions.end_frame();
1104 if (!selection->time.empty()) {
1105 pos = selection->time.end_frame ();
1113 if (cursor == playhead_cursor) {
1114 _session->request_locate (pos);
1116 cursor->set_position (pos);
1121 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1131 if (selection->markers.empty()) {
1135 if (!mouse_frame (mouse, ignored)) {
1139 add_location_mark (mouse);
1142 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1146 framepos_t pos = loc->start();
1148 // so we don't find the current region again..
1149 if (dir > 0 || pos > 0) {
1153 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1157 loc->move_to (target);
1161 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1163 selected_marker_to_region_boundary (with_selection, 1);
1167 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1169 selected_marker_to_region_boundary (with_selection, -1);
1173 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1175 boost::shared_ptr<Region> r;
1180 if (!_session || selection->markers.empty()) {
1184 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1188 TimeAxisView *ontrack = 0;
1192 // so we don't find the current region again..
1196 if (!selection->tracks.empty()) {
1198 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1202 r = find_next_region (pos, point, dir, track_views, &ontrack);
1211 pos = r->first_frame ();
1215 pos = r->last_frame ();
1219 pos = r->adjust_to_sync (r->first_frame());
1224 RouteTimeAxisView *rtav;
1226 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1227 if (rtav->track() != 0) {
1228 speed = rtav->track()->speed();
1232 pos = track_frame_to_session_frame(pos, speed);
1238 Editor::selected_marker_to_next_region_point (RegionPoint point)
1240 selected_marker_to_region_point (point, 1);
1244 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1246 selected_marker_to_region_point (point, -1);
1250 Editor::selected_marker_to_selection_start ()
1256 if (!_session || selection->markers.empty()) {
1260 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1264 switch (mouse_mode) {
1266 if (!selection->regions.empty()) {
1267 pos = selection->regions.start();
1272 if (!selection->time.empty()) {
1273 pos = selection->time.start ();
1285 Editor::selected_marker_to_selection_end ()
1291 if (!_session || selection->markers.empty()) {
1295 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1299 switch (mouse_mode) {
1301 if (!selection->regions.empty()) {
1302 pos = selection->regions.end_frame();
1307 if (!selection->time.empty()) {
1308 pos = selection->time.end_frame ();
1320 Editor::scroll_playhead (bool forward)
1322 framepos_t pos = playhead_cursor->current_frame ();
1323 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1326 if (pos == max_framepos) {
1330 if (pos < max_framepos - delta) {
1349 _session->request_locate (pos);
1353 Editor::cursor_align (bool playhead_to_edit)
1359 if (playhead_to_edit) {
1361 if (selection->markers.empty()) {
1365 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1368 /* move selected markers to playhead */
1370 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1373 Location* loc = find_location_from_marker (*i, ignored);
1375 if (loc->is_mark()) {
1376 loc->set_start (playhead_cursor->current_frame ());
1378 loc->set (playhead_cursor->current_frame (),
1379 playhead_cursor->current_frame () + loc->length());
1386 Editor::scroll_backward (float pages)
1388 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1389 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1392 if (leftmost_frame < cnt) {
1395 frame = leftmost_frame - cnt;
1398 reset_x_origin (frame);
1402 Editor::scroll_forward (float pages)
1404 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1405 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1408 if (max_framepos - cnt < leftmost_frame) {
1409 frame = max_framepos - cnt;
1411 frame = leftmost_frame + cnt;
1414 reset_x_origin (frame);
1418 Editor::scroll_tracks_down ()
1420 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1421 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1422 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1425 vertical_adjustment.set_value (vert_value);
1429 Editor::scroll_tracks_up ()
1431 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1435 Editor::scroll_tracks_down_line ()
1437 double vert_value = vertical_adjustment.get_value() + 60;
1439 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1440 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1443 vertical_adjustment.set_value (vert_value);
1447 Editor::scroll_tracks_up_line ()
1449 reset_y_origin (vertical_adjustment.get_value() - 60);
1453 Editor::scroll_down_one_track (bool skip_child_views)
1455 TrackViewList::reverse_iterator next = track_views.rend();
1456 const double top_of_trackviews = vertical_adjustment.get_value();
1458 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1459 if ((*t)->hidden()) {
1463 /* If this is the upper-most visible trackview, we want to display
1464 * the one above it (next)
1466 * Note that covers_y_position() is recursive and includes child views
1468 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1471 if (skip_child_views) {
1474 /* automation lane (one level, non-recursive)
1476 * - if no automation lane exists -> move to next tack
1477 * - if the first (here: bottom-most) matches -> move to next tack
1478 * - if no y-axis match is found -> the current track is at the top
1479 * -> move to last (here: top-most) automation lane
1481 TimeAxisView::Children kids = (*t)->get_child_list();
1482 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1484 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1485 if ((*ci)->hidden()) {
1489 std::pair<TimeAxisView*,double> dev;
1490 dev = (*ci)->covers_y_position (top_of_trackviews);
1492 /* some automation lane is currently at the top */
1493 if (ci == kids.rbegin()) {
1494 /* first (bottom-most) autmation lane is at the top.
1495 * -> move to next track
1504 if (nkid != kids.rend()) {
1505 ensure_time_axis_view_is_visible (**nkid, true);
1513 /* move to the track below the first one that covers the */
1515 if (next != track_views.rend()) {
1516 ensure_time_axis_view_is_visible (**next, true);
1524 Editor::scroll_up_one_track (bool skip_child_views)
1526 TrackViewList::iterator prev = track_views.end();
1527 double top_of_trackviews = vertical_adjustment.get_value ();
1529 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1531 if ((*t)->hidden()) {
1535 /* find the trackview at the top of the trackview group
1537 * Note that covers_y_position() is recursive and includes child views
1539 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1542 if (skip_child_views) {
1545 /* automation lane (one level, non-recursive)
1547 * - if no automation lane exists -> move to prev tack
1548 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1549 * (actually last automation lane of previous track, see below)
1550 * - if first (top-most) lane is at the top -> move to this track
1551 * - else move up one lane
1553 TimeAxisView::Children kids = (*t)->get_child_list();
1554 TimeAxisView::Children::iterator pkid = kids.end();
1556 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1557 if ((*ci)->hidden()) {
1561 std::pair<TimeAxisView*,double> dev;
1562 dev = (*ci)->covers_y_position (top_of_trackviews);
1564 /* some automation lane is currently at the top */
1565 if (ci == kids.begin()) {
1566 /* first (top-most) autmation lane is at the top.
1567 * jump directly to this track's top
1569 ensure_time_axis_view_is_visible (**t, true);
1572 else if (pkid != kids.end()) {
1573 /* some other automation lane is at the top.
1574 * move up to prev automation lane.
1576 ensure_time_axis_view_is_visible (**pkid, true);
1579 assert(0); // not reached
1590 if (prev != track_views.end()) {
1591 // move to bottom-most automation-lane of the previous track
1592 TimeAxisView::Children kids = (*prev)->get_child_list();
1593 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1594 if (!skip_child_views) {
1595 // find the last visible lane
1596 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1597 if (!(*ci)->hidden()) {
1603 if (pkid != kids.rend()) {
1604 ensure_time_axis_view_is_visible (**pkid, true);
1606 ensure_time_axis_view_is_visible (**prev, true);
1615 Editor::scroll_left_step ()
1617 framepos_t xdelta = (current_page_samples() / 8);
1619 if (leftmost_frame > xdelta) {
1620 reset_x_origin (leftmost_frame - xdelta);
1628 Editor::scroll_right_step ()
1630 framepos_t xdelta = (current_page_samples() / 8);
1632 if (max_framepos - xdelta > leftmost_frame) {
1633 reset_x_origin (leftmost_frame + xdelta);
1635 reset_x_origin (max_framepos - current_page_samples());
1640 Editor::scroll_left_half_page ()
1642 framepos_t xdelta = (current_page_samples() / 2);
1643 if (leftmost_frame > xdelta) {
1644 reset_x_origin (leftmost_frame - xdelta);
1651 Editor::scroll_right_half_page ()
1653 framepos_t xdelta = (current_page_samples() / 2);
1654 if (max_framepos - xdelta > leftmost_frame) {
1655 reset_x_origin (leftmost_frame + xdelta);
1657 reset_x_origin (max_framepos - current_page_samples());
1664 Editor::tav_zoom_step (bool coarser)
1666 DisplaySuspender ds;
1670 if (selection->tracks.empty()) {
1673 ts = &selection->tracks;
1676 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1677 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1678 tv->step_height (coarser);
1683 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1685 DisplaySuspender ds;
1689 if (selection->tracks.empty() || force_all) {
1692 ts = &selection->tracks;
1695 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1696 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1697 uint32_t h = tv->current_height ();
1702 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1707 tv->set_height (h + 5);
1713 Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1715 Editing::ZoomFocus temp_focus = zoom_focus;
1716 zoom_focus = Editing::ZoomFocusMouse;
1717 temporal_zoom_step_scale (zoom_out, scale);
1718 zoom_focus = temp_focus;
1722 Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1724 temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1728 Editor::temporal_zoom_step (bool zoom_out)
1730 temporal_zoom_step_scale (zoom_out, 2.0);
1734 Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1736 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1738 framecnt_t nspp = samples_per_pixel;
1742 if (nspp == samples_per_pixel) {
1747 if (nspp == samples_per_pixel) {
1752 temporal_zoom (nspp);
1756 Editor::temporal_zoom (framecnt_t fpp)
1762 framepos_t current_page = current_page_samples();
1763 framepos_t current_leftmost = leftmost_frame;
1764 framepos_t current_rightmost;
1765 framepos_t current_center;
1766 framepos_t new_page_size;
1767 framepos_t half_page_size;
1768 framepos_t leftmost_after_zoom = 0;
1770 bool in_track_canvas;
1771 bool use_mouse_frame = true;
1775 if (fpp == samples_per_pixel) {
1779 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1780 // segfaults for lack of memory. If somebody decides this is not high enough I
1781 // believe it can be raisen to higher values but some limit must be in place.
1783 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1784 // all of which is used for the editor track displays. The whole day
1785 // would be 4147200000 samples, so 2592000 samples per pixel.
1787 nfpp = min (fpp, (framecnt_t) 2592000);
1788 nfpp = max ((framecnt_t) 1, nfpp);
1790 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1791 half_page_size = new_page_size / 2;
1793 switch (zoom_focus) {
1795 leftmost_after_zoom = current_leftmost;
1798 case ZoomFocusRight:
1799 current_rightmost = leftmost_frame + current_page;
1800 if (current_rightmost < new_page_size) {
1801 leftmost_after_zoom = 0;
1803 leftmost_after_zoom = current_rightmost - new_page_size;
1807 case ZoomFocusCenter:
1808 current_center = current_leftmost + (current_page/2);
1809 if (current_center < half_page_size) {
1810 leftmost_after_zoom = 0;
1812 leftmost_after_zoom = current_center - half_page_size;
1816 case ZoomFocusPlayhead:
1817 /* centre playhead */
1818 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1821 leftmost_after_zoom = 0;
1822 } else if (l > max_framepos) {
1823 leftmost_after_zoom = max_framepos - new_page_size;
1825 leftmost_after_zoom = (framepos_t) l;
1829 case ZoomFocusMouse:
1830 /* try to keep the mouse over the same point in the display */
1832 if (_drags->active()) {
1833 where = _drags->current_pointer_frame ();
1834 } else if (!mouse_frame (where, in_track_canvas)) {
1835 use_mouse_frame = false;
1838 if (use_mouse_frame) {
1839 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1842 leftmost_after_zoom = 0;
1843 } else if (l > max_framepos) {
1844 leftmost_after_zoom = max_framepos - new_page_size;
1846 leftmost_after_zoom = (framepos_t) l;
1849 /* use playhead instead */
1850 where = playhead_cursor->current_frame ();
1852 if (where < half_page_size) {
1853 leftmost_after_zoom = 0;
1855 leftmost_after_zoom = where - half_page_size;
1861 /* try to keep the edit point in the same place */
1862 where = get_preferred_edit_position ();
1866 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1869 leftmost_after_zoom = 0;
1870 } else if (l > max_framepos) {
1871 leftmost_after_zoom = max_framepos - new_page_size;
1873 leftmost_after_zoom = (framepos_t) l;
1877 /* edit point not defined */
1884 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1886 reposition_and_zoom (leftmost_after_zoom, nfpp);
1890 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1892 /* this func helps make sure we leave a little space
1893 at each end of the editor so that the zoom doesn't fit the region
1894 precisely to the screen.
1897 GdkScreen* screen = gdk_screen_get_default ();
1898 const gint pixwidth = gdk_screen_get_width (screen);
1899 const gint mmwidth = gdk_screen_get_width_mm (screen);
1900 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1901 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1903 const framepos_t range = end - start;
1904 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1905 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1907 if (start > extra_samples) {
1908 start -= extra_samples;
1913 if (max_framepos - extra_samples > end) {
1914 end += extra_samples;
1921 Editor::temporal_zoom_region (bool both_axes)
1923 framepos_t start = max_framepos;
1925 set<TimeAxisView*> tracks;
1927 if ( !get_selection_extents(start, end) )
1930 calc_extra_zoom_edges (start, end);
1932 /* if we're zooming on both axes we need to save track heights etc.
1935 undo_visual_stack.push_back (current_visual_state (both_axes));
1937 PBD::Unwinder<bool> nsv (no_save_visual, true);
1939 temporal_zoom_by_frame (start, end);
1942 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1944 /* set visible track heights appropriately */
1946 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1947 (*t)->set_height (per_track_height);
1950 /* hide irrelevant tracks */
1952 DisplaySuspender ds;
1954 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1955 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1956 hide_track_in_display (*i);
1960 vertical_adjustment.set_value (0.0);
1963 redo_visual_stack.push_back (current_visual_state (both_axes));
1968 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1970 start = max_framepos;
1974 //ToDo: if notes are selected, set extents to that selection
1976 //ToDo: if control points are selected, set extents to that selection
1978 if ( !selection->regions.empty() ) {
1979 RegionSelection rs = get_regions_from_selection_and_entered ();
1981 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1983 if ((*i)->region()->position() < start) {
1984 start = (*i)->region()->position();
1987 if ((*i)->region()->last_frame() + 1 > end) {
1988 end = (*i)->region()->last_frame() + 1;
1992 } else if (!selection->time.empty()) {
1993 start = selection->time.start();
1994 end = selection->time.end_frame();
1996 ret = false; //no selection found
1999 if ((start == 0 && end == 0) || end < start) {
2008 Editor::temporal_zoom_selection (bool both_axes)
2010 if (!selection) return;
2012 //ToDo: if notes are selected, zoom to that
2014 //ToDo: if control points are selected, zoom to that
2016 //if region(s) are selected, zoom to that
2017 if ( !selection->regions.empty() )
2018 temporal_zoom_region (both_axes);
2020 //if a range is selected, zoom to that
2021 if (!selection->time.empty()) {
2023 framepos_t start, end;
2024 if (get_selection_extents (start, end)) {
2025 calc_extra_zoom_edges(start, end);
2026 temporal_zoom_by_frame (start, end);
2036 Editor::temporal_zoom_session ()
2038 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2041 framecnt_t start = _session->current_start_frame();
2042 framecnt_t end = _session->current_end_frame();
2044 if (_session->actively_recording () ) {
2045 framepos_t cur = playhead_cursor->current_frame ();
2047 /* recording beyond the end marker; zoom out
2048 * by 5 seconds more so that if 'follow
2049 * playhead' is active we don't immediately
2052 end = cur + _session->frame_rate() * 5;
2056 if ((start == 0 && end == 0) || end < start) {
2060 calc_extra_zoom_edges(start, end);
2062 temporal_zoom_by_frame (start, end);
2067 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2069 if (!_session) return;
2071 if ((start == 0 && end == 0) || end < start) {
2075 framepos_t range = end - start;
2077 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2079 framepos_t new_page = range;
2080 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2081 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2083 if (new_leftmost > middle) {
2087 if (new_leftmost < 0) {
2091 reposition_and_zoom (new_leftmost, new_fpp);
2095 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2101 framecnt_t range_before = frame - leftmost_frame;
2105 if (samples_per_pixel <= 1) {
2108 new_spp = samples_per_pixel + (samples_per_pixel/2);
2110 range_before += range_before/2;
2112 if (samples_per_pixel >= 1) {
2113 new_spp = samples_per_pixel - (samples_per_pixel/2);
2115 /* could bail out here since we cannot zoom any finer,
2116 but leave that to the equality test below
2118 new_spp = samples_per_pixel;
2121 range_before -= range_before/2;
2124 if (new_spp == samples_per_pixel) {
2128 /* zoom focus is automatically taken as @param frame when this
2132 framepos_t new_leftmost = frame - (framepos_t)range_before;
2134 if (new_leftmost > frame) {
2138 if (new_leftmost < 0) {
2142 reposition_and_zoom (new_leftmost, new_spp);
2147 Editor::choose_new_marker_name(string &name) {
2149 if (!UIConfiguration::instance().get_name_new_markers()) {
2150 /* don't prompt user for a new name */
2154 ArdourPrompter dialog (true);
2156 dialog.set_prompt (_("New Name:"));
2158 dialog.set_title (_("New Location Marker"));
2160 dialog.set_name ("MarkNameWindow");
2161 dialog.set_size_request (250, -1);
2162 dialog.set_position (Gtk::WIN_POS_MOUSE);
2164 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2165 dialog.set_initial_text (name);
2169 switch (dialog.run ()) {
2170 case RESPONSE_ACCEPT:
2176 dialog.get_result(name);
2183 Editor::add_location_from_selection ()
2187 if (selection->time.empty()) {
2191 if (_session == 0 || clicked_axisview == 0) {
2195 framepos_t start = selection->time[clicked_selection].start;
2196 framepos_t end = selection->time[clicked_selection].end;
2198 _session->locations()->next_available_name(rangename,"selection");
2199 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2201 begin_reversible_command (_("add marker"));
2203 XMLNode &before = _session->locations()->get_state();
2204 _session->locations()->add (location, true);
2205 XMLNode &after = _session->locations()->get_state();
2206 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2208 commit_reversible_command ();
2212 Editor::add_location_mark (framepos_t where)
2216 select_new_marker = true;
2218 _session->locations()->next_available_name(markername,"mark");
2219 if (!choose_new_marker_name(markername)) {
2222 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2223 begin_reversible_command (_("add marker"));
2225 XMLNode &before = _session->locations()->get_state();
2226 _session->locations()->add (location, true);
2227 XMLNode &after = _session->locations()->get_state();
2228 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2230 commit_reversible_command ();
2234 Editor::set_session_start_from_playhead ()
2240 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2241 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2243 XMLNode &before = loc->get_state();
2245 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2247 XMLNode &after = loc->get_state();
2249 begin_reversible_command (_("Set session start"));
2251 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2253 commit_reversible_command ();
2258 Editor::set_session_end_from_playhead ()
2264 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2265 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2267 XMLNode &before = loc->get_state();
2269 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2271 XMLNode &after = loc->get_state();
2273 begin_reversible_command (_("Set session start"));
2275 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2277 commit_reversible_command ();
2280 _session->set_end_is_free (false);
2285 Editor::toggle_location_at_playhead_cursor ()
2287 if (!do_remove_location_at_playhead_cursor())
2289 add_location_from_playhead_cursor();
2294 Editor::add_location_from_playhead_cursor ()
2296 add_location_mark (_session->audible_frame());
2300 Editor::do_remove_location_at_playhead_cursor ()
2302 bool removed = false;
2305 XMLNode &before = _session->locations()->get_state();
2307 //find location(s) at this time
2308 Locations::LocationList locs;
2309 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2310 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2311 if ((*i)->is_mark()) {
2312 _session->locations()->remove (*i);
2319 begin_reversible_command (_("remove marker"));
2320 XMLNode &after = _session->locations()->get_state();
2321 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2322 commit_reversible_command ();
2329 Editor::remove_location_at_playhead_cursor ()
2331 do_remove_location_at_playhead_cursor ();
2334 /** Add a range marker around each selected region */
2336 Editor::add_locations_from_region ()
2338 RegionSelection rs = get_regions_from_selection_and_entered ();
2343 bool commit = false;
2345 XMLNode &before = _session->locations()->get_state();
2347 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2349 boost::shared_ptr<Region> region = (*i)->region ();
2351 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2353 _session->locations()->add (location, true);
2358 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2359 XMLNode &after = _session->locations()->get_state();
2360 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2361 commit_reversible_command ();
2365 /** Add a single range marker around all selected regions */
2367 Editor::add_location_from_region ()
2369 RegionSelection rs = get_regions_from_selection_and_entered ();
2375 XMLNode &before = _session->locations()->get_state();
2379 if (rs.size() > 1) {
2380 _session->locations()->next_available_name(markername, "regions");
2382 RegionView* rv = *(rs.begin());
2383 boost::shared_ptr<Region> region = rv->region();
2384 markername = region->name();
2387 if (!choose_new_marker_name(markername)) {
2391 // single range spanning all selected
2392 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2393 _session->locations()->add (location, true);
2395 begin_reversible_command (_("add marker"));
2396 XMLNode &after = _session->locations()->get_state();
2397 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2398 commit_reversible_command ();
2404 Editor::jump_forward_to_mark ()
2410 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2416 _session->request_locate (pos, _session->transport_rolling());
2420 Editor::jump_backward_to_mark ()
2426 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2432 _session->request_locate (pos, _session->transport_rolling());
2438 framepos_t const pos = _session->audible_frame ();
2441 _session->locations()->next_available_name (markername, "mark");
2443 if (!choose_new_marker_name (markername)) {
2447 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2451 Editor::clear_markers ()
2454 begin_reversible_command (_("clear markers"));
2456 XMLNode &before = _session->locations()->get_state();
2457 _session->locations()->clear_markers ();
2458 XMLNode &after = _session->locations()->get_state();
2459 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2461 commit_reversible_command ();
2466 Editor::clear_ranges ()
2469 begin_reversible_command (_("clear ranges"));
2471 XMLNode &before = _session->locations()->get_state();
2473 _session->locations()->clear_ranges ();
2475 XMLNode &after = _session->locations()->get_state();
2476 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2478 commit_reversible_command ();
2483 Editor::clear_locations ()
2485 begin_reversible_command (_("clear locations"));
2487 XMLNode &before = _session->locations()->get_state();
2488 _session->locations()->clear ();
2489 XMLNode &after = _session->locations()->get_state();
2490 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2492 commit_reversible_command ();
2496 Editor::unhide_markers ()
2498 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2499 Location *l = (*i).first;
2500 if (l->is_hidden() && l->is_mark()) {
2501 l->set_hidden(false, this);
2507 Editor::unhide_ranges ()
2509 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2510 Location *l = (*i).first;
2511 if (l->is_hidden() && l->is_range_marker()) {
2512 l->set_hidden(false, this);
2517 /* INSERT/REPLACE */
2520 Editor::insert_region_list_selection (float times)
2522 RouteTimeAxisView *tv = 0;
2523 boost::shared_ptr<Playlist> playlist;
2525 if (clicked_routeview != 0) {
2526 tv = clicked_routeview;
2527 } else if (!selection->tracks.empty()) {
2528 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2531 } else if (entered_track != 0) {
2532 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2539 if ((playlist = tv->playlist()) == 0) {
2543 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2548 begin_reversible_command (_("insert region"));
2549 playlist->clear_changes ();
2550 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2551 if (Config->get_edit_mode() == Ripple)
2552 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2554 _session->add_command(new StatefulDiffCommand (playlist));
2555 commit_reversible_command ();
2558 /* BUILT-IN EFFECTS */
2561 Editor::reverse_selection ()
2566 /* GAIN ENVELOPE EDITING */
2569 Editor::edit_envelope ()
2576 Editor::transition_to_rolling (bool fwd)
2582 if (_session->config.get_external_sync()) {
2583 switch (Config->get_sync_source()) {
2587 /* transport controlled by the master */
2592 if (_session->is_auditioning()) {
2593 _session->cancel_audition ();
2597 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2601 Editor::play_from_start ()
2603 _session->request_locate (_session->current_start_frame(), true);
2607 Editor::play_from_edit_point ()
2609 _session->request_locate (get_preferred_edit_position(), true);
2613 Editor::play_from_edit_point_and_return ()
2615 framepos_t start_frame;
2616 framepos_t return_frame;
2618 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2620 if (_session->transport_rolling()) {
2621 _session->request_locate (start_frame, false);
2625 /* don't reset the return frame if its already set */
2627 if ((return_frame = _session->requested_return_frame()) < 0) {
2628 return_frame = _session->audible_frame();
2631 if (start_frame >= 0) {
2632 _session->request_roll_at_and_return (start_frame, return_frame);
2637 Editor::play_selection ()
2639 framepos_t start, end;
2640 if (!get_selection_extents ( start, end))
2643 AudioRange ar (start, end, 0);
2644 list<AudioRange> lar;
2647 _session->request_play_range (&lar, true);
2651 Editor::get_preroll ()
2653 return Config->get_preroll_seconds() * _session->frame_rate();
2658 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2660 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2663 location -= get_preroll();
2665 //don't try to locate before the beginning of time
2669 //if follow_playhead is on, keep the playhead on the screen
2670 if ( _follow_playhead )
2671 if ( location < leftmost_frame )
2672 location = leftmost_frame;
2674 _session->request_locate( location );
2678 Editor::play_with_preroll ()
2681 framepos_t preroll = get_preroll();
2683 framepos_t start, end;
2684 if (!get_selection_extents ( start, end))
2687 if (start > preroll)
2688 start = start - preroll;
2690 end = end + preroll; //"post-roll"
2692 AudioRange ar (start, end, 0);
2693 list<AudioRange> lar;
2696 _session->request_play_range (&lar, true);
2701 Editor::play_location (Location& location)
2703 if (location.start() <= location.end()) {
2707 _session->request_bounded_roll (location.start(), location.end());
2711 Editor::loop_location (Location& location)
2713 if (location.start() <= location.end()) {
2719 if ((tll = transport_loop_location()) != 0) {
2720 tll->set (location.start(), location.end());
2722 // enable looping, reposition and start rolling
2723 _session->request_locate (tll->start(), true);
2724 _session->request_play_loop (true);
2729 Editor::do_layer_operation (LayerOperation op)
2731 if (selection->regions.empty ()) {
2735 bool const multiple = selection->regions.size() > 1;
2739 begin_reversible_command (_("raise regions"));
2741 begin_reversible_command (_("raise region"));
2747 begin_reversible_command (_("raise regions to top"));
2749 begin_reversible_command (_("raise region to top"));
2755 begin_reversible_command (_("lower regions"));
2757 begin_reversible_command (_("lower region"));
2763 begin_reversible_command (_("lower regions to bottom"));
2765 begin_reversible_command (_("lower region"));
2770 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2771 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2772 (*i)->clear_owned_changes ();
2775 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2776 boost::shared_ptr<Region> r = (*i)->region ();
2788 r->lower_to_bottom ();
2792 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2793 vector<Command*> cmds;
2795 _session->add_commands (cmds);
2798 commit_reversible_command ();
2802 Editor::raise_region ()
2804 do_layer_operation (Raise);
2808 Editor::raise_region_to_top ()
2810 do_layer_operation (RaiseToTop);
2814 Editor::lower_region ()
2816 do_layer_operation (Lower);
2820 Editor::lower_region_to_bottom ()
2822 do_layer_operation (LowerToBottom);
2825 /** Show the region editor for the selected regions */
2827 Editor::show_region_properties ()
2829 selection->foreach_regionview (&RegionView::show_region_editor);
2832 /** Show the midi list editor for the selected MIDI regions */
2834 Editor::show_midi_list_editor ()
2836 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2840 Editor::rename_region ()
2842 RegionSelection rs = get_regions_from_selection_and_entered ();
2848 ArdourDialog d (_("Rename Region"), true, false);
2850 Label label (_("New name:"));
2853 hbox.set_spacing (6);
2854 hbox.pack_start (label, false, false);
2855 hbox.pack_start (entry, true, true);
2857 d.get_vbox()->set_border_width (12);
2858 d.get_vbox()->pack_start (hbox, false, false);
2860 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2861 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2863 d.set_size_request (300, -1);
2865 entry.set_text (rs.front()->region()->name());
2866 entry.select_region (0, -1);
2868 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2874 int const ret = d.run();
2878 if (ret != RESPONSE_OK) {
2882 std::string str = entry.get_text();
2883 strip_whitespace_edges (str);
2885 rs.front()->region()->set_name (str);
2886 _regions->redisplay ();
2890 /** Start an audition of the first selected region */
2892 Editor::play_edit_range ()
2894 framepos_t start, end;
2896 if (get_edit_op_range (start, end)) {
2897 _session->request_bounded_roll (start, end);
2902 Editor::play_selected_region ()
2904 framepos_t start = max_framepos;
2907 RegionSelection rs = get_regions_from_selection_and_entered ();
2913 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2914 if ((*i)->region()->position() < start) {
2915 start = (*i)->region()->position();
2917 if ((*i)->region()->last_frame() + 1 > end) {
2918 end = (*i)->region()->last_frame() + 1;
2922 _session->request_bounded_roll (start, end);
2926 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2928 _session->audition_region (region);
2932 Editor::region_from_selection ()
2934 if (clicked_axisview == 0) {
2938 if (selection->time.empty()) {
2942 framepos_t start = selection->time[clicked_selection].start;
2943 framepos_t end = selection->time[clicked_selection].end;
2945 TrackViewList tracks = get_tracks_for_range_action ();
2947 framepos_t selection_cnt = end - start + 1;
2949 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2950 boost::shared_ptr<Region> current;
2951 boost::shared_ptr<Playlist> pl;
2952 framepos_t internal_start;
2955 if ((pl = (*i)->playlist()) == 0) {
2959 if ((current = pl->top_region_at (start)) == 0) {
2963 internal_start = start - current->position();
2964 RegionFactory::region_name (new_name, current->name(), true);
2968 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2969 plist.add (ARDOUR::Properties::length, selection_cnt);
2970 plist.add (ARDOUR::Properties::name, new_name);
2971 plist.add (ARDOUR::Properties::layer, 0);
2973 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2978 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2980 if (selection->time.empty() || selection->tracks.empty()) {
2984 framepos_t start, end;
2985 if (clicked_selection) {
2986 start = selection->time[clicked_selection].start;
2987 end = selection->time[clicked_selection].end;
2989 start = selection->time.start();
2990 end = selection->time.end_frame();
2993 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2994 sort_track_selection (ts);
2996 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2997 boost::shared_ptr<Region> current;
2998 boost::shared_ptr<Playlist> playlist;
2999 framepos_t internal_start;
3002 if ((playlist = (*i)->playlist()) == 0) {
3006 if ((current = playlist->top_region_at(start)) == 0) {
3010 internal_start = start - current->position();
3011 RegionFactory::region_name (new_name, current->name(), true);
3015 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3016 plist.add (ARDOUR::Properties::length, end - start + 1);
3017 plist.add (ARDOUR::Properties::name, new_name);
3019 new_regions.push_back (RegionFactory::create (current, plist));
3024 Editor::split_multichannel_region ()
3026 RegionSelection rs = get_regions_from_selection_and_entered ();
3032 vector< boost::shared_ptr<Region> > v;
3034 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3035 (*x)->region()->separate_by_channel (*_session, v);
3040 Editor::new_region_from_selection ()
3042 region_from_selection ();
3043 cancel_selection ();
3047 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3049 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3050 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3051 case Evoral::OverlapNone:
3059 * - selected tracks, or if there are none...
3060 * - tracks containing selected regions, or if there are none...
3065 Editor::get_tracks_for_range_action () const
3069 if (selection->tracks.empty()) {
3071 /* use tracks with selected regions */
3073 RegionSelection rs = selection->regions;
3075 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3076 TimeAxisView* tv = &(*i)->get_time_axis_view();
3078 if (!t.contains (tv)) {
3084 /* no regions and no tracks: use all tracks */
3090 t = selection->tracks;
3093 return t.filter_to_unique_playlists();
3097 Editor::separate_regions_between (const TimeSelection& ts)
3099 bool in_command = false;
3100 boost::shared_ptr<Playlist> playlist;
3101 RegionSelection new_selection;
3103 TrackViewList tmptracks = get_tracks_for_range_action ();
3104 sort_track_selection (tmptracks);
3106 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3108 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3114 if (!rtv->is_track()) {
3118 /* no edits to destructive tracks */
3120 if (rtv->track()->destructive()) {
3124 if ((playlist = rtv->playlist()) != 0) {
3126 playlist->clear_changes ();
3128 /* XXX need to consider musical time selections here at some point */
3130 double speed = rtv->track()->speed();
3132 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3134 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3135 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3137 latest_regionviews.clear ();
3139 playlist->partition ((framepos_t)((*t).start * speed),
3140 (framepos_t)((*t).end * speed), false);
3144 if (!latest_regionviews.empty()) {
3146 rtv->view()->foreach_regionview (sigc::bind (
3147 sigc::ptr_fun (add_if_covered),
3148 &(*t), &new_selection));
3151 begin_reversible_command (_("separate"));
3155 /* pick up changes to existing regions */
3157 vector<Command*> cmds;
3158 playlist->rdiff (cmds);
3159 _session->add_commands (cmds);
3161 /* pick up changes to the playlist itself (adds/removes)
3164 _session->add_command(new StatefulDiffCommand (playlist));
3171 // selection->set (new_selection);
3173 commit_reversible_command ();
3177 struct PlaylistState {
3178 boost::shared_ptr<Playlist> playlist;
3182 /** Take tracks from get_tracks_for_range_action and cut any regions
3183 * on those tracks so that the tracks are empty over the time
3187 Editor::separate_region_from_selection ()
3189 /* preferentially use *all* ranges in the time selection if we're in range mode
3190 to allow discontiguous operation, since get_edit_op_range() currently
3191 returns a single range.
3194 if (!selection->time.empty()) {
3196 separate_regions_between (selection->time);
3203 if (get_edit_op_range (start, end)) {
3205 AudioRange ar (start, end, 1);
3209 separate_regions_between (ts);
3215 Editor::separate_region_from_punch ()
3217 Location* loc = _session->locations()->auto_punch_location();
3219 separate_regions_using_location (*loc);
3224 Editor::separate_region_from_loop ()
3226 Location* loc = _session->locations()->auto_loop_location();
3228 separate_regions_using_location (*loc);
3233 Editor::separate_regions_using_location (Location& loc)
3235 if (loc.is_mark()) {
3239 AudioRange ar (loc.start(), loc.end(), 1);
3244 separate_regions_between (ts);
3247 /** Separate regions under the selected region */
3249 Editor::separate_under_selected_regions ()
3251 vector<PlaylistState> playlists;
3255 rs = get_regions_from_selection_and_entered();
3257 if (!_session || rs.empty()) {
3261 begin_reversible_command (_("separate region under"));
3263 list<boost::shared_ptr<Region> > regions_to_remove;
3265 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3266 // we can't just remove the region(s) in this loop because
3267 // this removes them from the RegionSelection, and they thus
3268 // disappear from underneath the iterator, and the ++i above
3269 // SEGVs in a puzzling fashion.
3271 // so, first iterate over the regions to be removed from rs and
3272 // add them to the regions_to_remove list, and then
3273 // iterate over the list to actually remove them.
3275 regions_to_remove.push_back ((*i)->region());
3278 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3280 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3283 // is this check necessary?
3287 vector<PlaylistState>::iterator i;
3289 //only take state if this is a new playlist.
3290 for (i = playlists.begin(); i != playlists.end(); ++i) {
3291 if ((*i).playlist == playlist) {
3296 if (i == playlists.end()) {
3298 PlaylistState before;
3299 before.playlist = playlist;
3300 before.before = &playlist->get_state();
3302 playlist->freeze ();
3303 playlists.push_back(before);
3306 //Partition on the region bounds
3307 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3309 //Re-add region that was just removed due to the partition operation
3310 playlist->add_region( (*rl), (*rl)->first_frame() );
3313 vector<PlaylistState>::iterator pl;
3315 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3316 (*pl).playlist->thaw ();
3317 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3320 commit_reversible_command ();
3324 Editor::crop_region_to_selection ()
3326 if (!selection->time.empty()) {
3328 crop_region_to (selection->time.start(), selection->time.end_frame());
3335 if (get_edit_op_range (start, end)) {
3336 crop_region_to (start, end);
3343 Editor::crop_region_to (framepos_t start, framepos_t end)
3345 vector<boost::shared_ptr<Playlist> > playlists;
3346 boost::shared_ptr<Playlist> playlist;
3349 if (selection->tracks.empty()) {
3350 ts = track_views.filter_to_unique_playlists();
3352 ts = selection->tracks.filter_to_unique_playlists ();
3355 sort_track_selection (ts);
3357 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3359 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3365 boost::shared_ptr<Track> t = rtv->track();
3367 if (t != 0 && ! t->destructive()) {
3369 if ((playlist = rtv->playlist()) != 0) {
3370 playlists.push_back (playlist);
3375 if (playlists.empty()) {
3380 framepos_t new_start;
3382 framecnt_t new_length;
3383 bool in_command = false;
3385 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3387 /* Only the top regions at start and end have to be cropped */
3388 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3389 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3391 vector<boost::shared_ptr<Region> > regions;
3393 if (region_at_start != 0) {
3394 regions.push_back (region_at_start);
3396 if (region_at_end != 0) {
3397 regions.push_back (region_at_end);
3400 /* now adjust lengths */
3401 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3403 pos = (*i)->position();
3404 new_start = max (start, pos);
3405 if (max_framepos - pos > (*i)->length()) {
3406 new_end = pos + (*i)->length() - 1;
3408 new_end = max_framepos;
3410 new_end = min (end, new_end);
3411 new_length = new_end - new_start + 1;
3414 begin_reversible_command (_("trim to selection"));
3417 (*i)->clear_changes ();
3418 (*i)->trim_to (new_start, new_length);
3419 _session->add_command (new StatefulDiffCommand (*i));
3424 commit_reversible_command ();
3429 Editor::region_fill_track ()
3431 boost::shared_ptr<Playlist> playlist;
3432 RegionSelection regions = get_regions_from_selection_and_entered ();
3433 RegionSelection foo;
3435 framepos_t const end = _session->current_end_frame ();
3437 if (regions.empty () || regions.end_frame () + 1 >= end) {
3441 framepos_t const start_frame = regions.start ();
3442 framepos_t const end_frame = regions.end_frame ();
3443 framecnt_t const gap = end_frame - start_frame + 1;
3445 begin_reversible_command (Operations::region_fill);
3447 selection->clear_regions ();
3449 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3451 boost::shared_ptr<Region> r ((*i)->region());
3453 TimeAxisView& tv = (*i)->get_time_axis_view();
3454 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3455 latest_regionviews.clear ();
3456 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3458 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3459 playlist = (*i)->region()->playlist();
3460 playlist->clear_changes ();
3461 playlist->duplicate_until (r, position, gap, end);
3462 _session->add_command(new StatefulDiffCommand (playlist));
3466 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3470 selection->set (foo);
3473 commit_reversible_command ();
3477 Editor::set_region_sync_position ()
3479 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3483 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3485 bool in_command = false;
3487 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3489 if (!(*r)->region()->covers (where)) {
3493 boost::shared_ptr<Region> region ((*r)->region());
3496 begin_reversible_command (_("set sync point"));
3500 region->clear_changes ();
3501 region->set_sync_position (where);
3502 _session->add_command(new StatefulDiffCommand (region));
3506 commit_reversible_command ();
3510 /** Remove the sync positions of the selection */
3512 Editor::remove_region_sync ()
3514 RegionSelection rs = get_regions_from_selection_and_entered ();
3520 begin_reversible_command (_("remove region sync"));
3522 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3524 (*i)->region()->clear_changes ();
3525 (*i)->region()->clear_sync_position ();
3526 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3529 commit_reversible_command ();
3533 Editor::naturalize_region ()
3535 RegionSelection rs = get_regions_from_selection_and_entered ();
3541 if (rs.size() > 1) {
3542 begin_reversible_command (_("move regions to original position"));
3544 begin_reversible_command (_("move region to original position"));
3547 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3548 (*i)->region()->clear_changes ();
3549 (*i)->region()->move_to_natural_position ();
3550 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3553 commit_reversible_command ();
3557 Editor::align_regions (RegionPoint what)
3559 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3565 begin_reversible_command (_("align selection"));
3567 framepos_t const position = get_preferred_edit_position ();
3569 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3570 align_region_internal ((*i)->region(), what, position);
3573 commit_reversible_command ();
3576 struct RegionSortByTime {
3577 bool operator() (const RegionView* a, const RegionView* b) {
3578 return a->region()->position() < b->region()->position();
3583 Editor::align_regions_relative (RegionPoint point)
3585 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3591 framepos_t const position = get_preferred_edit_position ();
3593 framepos_t distance = 0;
3597 list<RegionView*> sorted;
3598 rs.by_position (sorted);
3600 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3605 if (position > r->position()) {
3606 distance = position - r->position();
3608 distance = r->position() - position;
3614 if (position > r->last_frame()) {
3615 distance = position - r->last_frame();
3616 pos = r->position() + distance;
3618 distance = r->last_frame() - position;
3619 pos = r->position() - distance;
3625 pos = r->adjust_to_sync (position);
3626 if (pos > r->position()) {
3627 distance = pos - r->position();
3629 distance = r->position() - pos;
3635 if (pos == r->position()) {
3639 begin_reversible_command (_("align selection (relative)"));
3641 /* move first one specially */
3643 r->clear_changes ();
3644 r->set_position (pos);
3645 _session->add_command(new StatefulDiffCommand (r));
3647 /* move rest by the same amount */
3651 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3653 boost::shared_ptr<Region> region ((*i)->region());
3655 region->clear_changes ();
3658 region->set_position (region->position() + distance);
3660 region->set_position (region->position() - distance);
3663 _session->add_command(new StatefulDiffCommand (region));
3667 commit_reversible_command ();
3671 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3673 begin_reversible_command (_("align region"));
3674 align_region_internal (region, point, position);
3675 commit_reversible_command ();
3679 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3681 region->clear_changes ();
3685 region->set_position (region->adjust_to_sync (position));
3689 if (position > region->length()) {
3690 region->set_position (position - region->length());
3695 region->set_position (position);
3699 _session->add_command(new StatefulDiffCommand (region));
3703 Editor::trim_region_front ()
3709 Editor::trim_region_back ()
3711 trim_region (false);
3715 Editor::trim_region (bool front)
3717 framepos_t where = get_preferred_edit_position();
3718 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3724 begin_reversible_command (front ? _("trim front") : _("trim back"));
3726 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3727 if (!(*i)->region()->locked()) {
3729 (*i)->region()->clear_changes ();
3732 (*i)->region()->trim_front (where);
3733 maybe_locate_with_edit_preroll ( where );
3735 (*i)->region()->trim_end (where);
3736 maybe_locate_with_edit_preroll ( where );
3739 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3743 commit_reversible_command ();
3746 /** Trim the end of the selected regions to the position of the edit cursor */
3748 Editor::trim_region_to_loop ()
3750 Location* loc = _session->locations()->auto_loop_location();
3754 trim_region_to_location (*loc, _("trim to loop"));
3758 Editor::trim_region_to_punch ()
3760 Location* loc = _session->locations()->auto_punch_location();
3764 trim_region_to_location (*loc, _("trim to punch"));
3768 Editor::trim_region_to_location (const Location& loc, const char* str)
3770 RegionSelection rs = get_regions_from_selection_and_entered ();
3771 bool in_command = false;
3773 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3774 RegionView* rv = (*x);
3776 /* require region to span proposed trim */
3777 switch (rv->region()->coverage (loc.start(), loc.end())) {
3778 case Evoral::OverlapInternal:
3784 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3793 if (tav->track() != 0) {
3794 speed = tav->track()->speed();
3797 start = session_frame_to_track_frame (loc.start(), speed);
3798 end = session_frame_to_track_frame (loc.end(), speed);
3800 rv->region()->clear_changes ();
3801 rv->region()->trim_to (start, (end - start));
3804 begin_reversible_command (str);
3807 _session->add_command(new StatefulDiffCommand (rv->region()));
3811 commit_reversible_command ();
3816 Editor::trim_region_to_previous_region_end ()
3818 return trim_to_region(false);
3822 Editor::trim_region_to_next_region_start ()
3824 return trim_to_region(true);
3828 Editor::trim_to_region(bool forward)
3830 RegionSelection rs = get_regions_from_selection_and_entered ();
3831 bool in_command = false;
3833 boost::shared_ptr<Region> next_region;
3835 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3837 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3843 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3851 if (atav->track() != 0) {
3852 speed = atav->track()->speed();
3856 boost::shared_ptr<Region> region = arv->region();
3857 boost::shared_ptr<Playlist> playlist (region->playlist());
3859 region->clear_changes ();
3863 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3869 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3870 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3874 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3880 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3882 arv->region_changed (ARDOUR::bounds_change);
3886 begin_reversible_command (_("trim to region"));
3889 _session->add_command(new StatefulDiffCommand (region));
3893 commit_reversible_command ();
3898 Editor::unfreeze_route ()
3900 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3904 clicked_routeview->track()->unfreeze ();
3908 Editor::_freeze_thread (void* arg)
3910 return static_cast<Editor*>(arg)->freeze_thread ();
3914 Editor::freeze_thread ()
3916 /* create event pool because we may need to talk to the session */
3917 SessionEvent::create_per_thread_pool ("freeze events", 64);
3918 /* create per-thread buffers for process() tree to use */
3919 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3920 current_interthread_info->done = true;
3925 Editor::freeze_route ()
3931 /* stop transport before we start. this is important */
3933 _session->request_transport_speed (0.0);
3935 /* wait for just a little while, because the above call is asynchronous */
3937 Glib::usleep (250000);
3939 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3943 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3945 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3946 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3948 d.set_title (_("Cannot freeze"));
3953 if (clicked_routeview->track()->has_external_redirects()) {
3954 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"
3955 "Freezing will only process the signal as far as the first send/insert/return."),
3956 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3958 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3959 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3960 d.set_title (_("Freeze Limits"));
3962 int response = d.run ();
3965 case Gtk::RESPONSE_CANCEL:
3972 InterThreadInfo itt;
3973 current_interthread_info = &itt;
3975 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3977 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3979 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3981 while (!itt.done && !itt.cancel) {
3982 gtk_main_iteration ();
3985 pthread_join (itt.thread, 0);
3986 current_interthread_info = 0;
3990 Editor::bounce_range_selection (bool replace, bool enable_processing)
3992 if (selection->time.empty()) {
3996 TrackSelection views = selection->tracks;
3998 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4000 if (enable_processing) {
4002 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4004 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
4006 _("You can't perform this operation because the processing of the signal "
4007 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
4008 "You can do this without processing, which is a different operation.")
4010 d.set_title (_("Cannot bounce"));
4017 framepos_t start = selection->time[clicked_selection].start;
4018 framepos_t end = selection->time[clicked_selection].end;
4019 framepos_t cnt = end - start + 1;
4020 bool in_command = false;
4022 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4024 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4030 boost::shared_ptr<Playlist> playlist;
4032 if ((playlist = rtv->playlist()) == 0) {
4036 InterThreadInfo itt;
4038 playlist->clear_changes ();
4039 playlist->clear_owned_changes ();
4041 boost::shared_ptr<Region> r;
4043 if (enable_processing) {
4044 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4046 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4054 list<AudioRange> ranges;
4055 ranges.push_back (AudioRange (start, start+cnt, 0));
4056 playlist->cut (ranges); // discard result
4057 playlist->add_region (r, start);
4061 begin_reversible_command (_("bounce range"));
4064 vector<Command*> cmds;
4065 playlist->rdiff (cmds);
4066 _session->add_commands (cmds);
4068 _session->add_command (new StatefulDiffCommand (playlist));
4072 commit_reversible_command ();
4076 /** Delete selected regions, automation points or a time range */
4080 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4081 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4082 bool deleted = false;
4083 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4084 deleted = current_mixer_strip->delete_processors ();
4090 /** Cut selected regions, automation points or a time range */
4097 /** Copy selected regions, automation points or a time range */
4105 /** @return true if a Cut, Copy or Clear is possible */
4107 Editor::can_cut_copy () const
4109 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4116 /** Cut, copy or clear selected regions, automation points or a time range.
4117 * @param op Operation (Delete, Cut, Copy or Clear)
4120 Editor::cut_copy (CutCopyOp op)
4122 /* only cancel selection if cut/copy is successful.*/
4128 opname = _("delete");
4137 opname = _("clear");
4141 /* if we're deleting something, and the mouse is still pressed,
4142 the thing we started a drag for will be gone when we release
4143 the mouse button(s). avoid this. see part 2 at the end of
4147 if (op == Delete || op == Cut || op == Clear) {
4148 if (_drags->active ()) {
4153 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4154 cut_buffer->clear ();
4156 if (entered_marker) {
4158 /* cut/delete op while pointing at a marker */
4161 Location* loc = find_location_from_marker (entered_marker, ignored);
4163 if (_session && loc) {
4164 entered_marker = NULL;
4165 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4172 switch (mouse_mode) {
4175 begin_reversible_command (opname + ' ' + X_("MIDI"));
4177 commit_reversible_command ();
4183 bool did_edit = false;
4185 if (!selection->regions.empty() || !selection->points.empty()) {
4186 begin_reversible_command (opname + ' ' + _("objects"));
4189 if (!selection->regions.empty()) {
4190 cut_copy_regions (op, selection->regions);
4192 if (op == Cut || op == Delete) {
4193 selection->clear_regions ();
4197 if (!selection->points.empty()) {
4198 cut_copy_points (op);
4200 if (op == Cut || op == Delete) {
4201 selection->clear_points ();
4204 } else if (selection->time.empty()) {
4205 framepos_t start, end;
4206 /* no time selection, see if we can get an edit range
4209 if (get_edit_op_range (start, end)) {
4210 selection->set (start, end);
4212 } else if (!selection->time.empty()) {
4213 begin_reversible_command (opname + ' ' + _("range"));
4216 cut_copy_ranges (op);
4218 if (op == Cut || op == Delete) {
4219 selection->clear_time ();
4224 /* reset repeated paste state */
4227 commit_reversible_command ();
4230 if (op == Delete || op == Cut || op == Clear) {
4236 struct AutomationRecord {
4237 AutomationRecord () : state (0) , line(NULL) {}
4238 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4240 XMLNode* state; ///< state before any operation
4241 const AutomationLine* line; ///< line this came from
4242 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4244 struct PointsSelectionPositionSorter {
4245 bool operator() (ControlPoint* a, ControlPoint* b) {
4246 return (*(a->model()))->when < (*(b->model()))->when;
4249 /** Cut, copy or clear selected automation points.
4250 * @param op Operation (Cut, Copy or Clear)
4253 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4255 if (selection->points.empty ()) {
4259 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4260 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4262 /* Keep a record of the AutomationLists that we end up using in this operation */
4263 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4266 /* user could select points in any order */
4267 selection->points.sort(PointsSelectionPositionSorter ());
4269 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4270 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4271 const AutomationLine& line = (*sel_point)->line();
4272 const boost::shared_ptr<AutomationList> al = line.the_list();
4273 if (lists.find (al) == lists.end ()) {
4274 /* We haven't seen this list yet, so make a record for it. This includes
4275 taking a copy of its current state, in case this is needed for undo later.
4277 lists[al] = AutomationRecord (&al->get_state (), &line);
4281 if (op == Cut || op == Copy) {
4282 /* This operation will involve putting things in the cut buffer, so create an empty
4283 ControlList for each of our source lists to put the cut buffer data in.
4285 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4286 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4289 /* Add all selected points to the relevant copy ControlLists */
4290 framepos_t start = std::numeric_limits<framepos_t>::max();
4291 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4292 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4293 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4295 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4297 /* Update earliest MIDI start time in beats */
4298 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4300 /* Update earliest session start time in frames */
4301 start = std::min(start, (*sel_point)->line().session_position(ctrl_evt));
4305 /* Snap start time backwards, so copy/paste is snap aligned. */
4307 if (earliest == Evoral::Beats::max()) {
4308 earliest = Evoral::Beats(); // Weird... don't offset
4310 earliest.round_down_to_beat();
4312 if (start == std::numeric_limits<double>::max()) {
4313 start = 0; // Weird... don't offset
4315 snap_to(start, RoundDownMaybe);
4318 const double line_offset = midi ? earliest.to_double() : start;
4319 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4320 /* Correct this copy list so that it is relative to the earliest
4321 start time, so relative ordering between points is preserved
4322 when copying from several lists and the paste starts at the
4323 earliest copied piece of data. */
4324 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4325 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4326 (*ctrl_evt)->when -= line_offset;
4329 /* And add it to the cut buffer */
4330 cut_buffer->add (al_cpy);
4334 if (op == Delete || op == Cut) {
4335 /* This operation needs to remove things from the main AutomationList, so do that now */
4337 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4338 i->first->freeze ();
4341 /* Remove each selected point from its AutomationList */
4342 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4343 AutomationLine& line = (*sel_point)->line ();
4344 boost::shared_ptr<AutomationList> al = line.the_list();
4348 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4349 /* removing of first and last gain point in region gain lines is prohibited*/
4350 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4356 al->erase ((*sel_point)->model ());
4360 /* Thaw the lists and add undo records for them */
4361 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4362 boost::shared_ptr<AutomationList> al = i->first;
4364 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4369 /** Cut, copy or clear selected automation points.
4370 * @param op Operation (Cut, Copy or Clear)
4373 Editor::cut_copy_midi (CutCopyOp op)
4375 Evoral::Beats earliest = Evoral::Beats::max();
4376 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4377 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4379 if (!mrv->selection().empty()) {
4380 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4382 mrv->cut_copy_clear (op);
4384 /* XXX: not ideal, as there may be more than one track involved in the selection */
4385 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4389 if (!selection->points.empty()) {
4390 cut_copy_points (op, earliest, true);
4391 if (op == Cut || op == Delete) {
4392 selection->clear_points ();
4397 struct lt_playlist {
4398 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4399 return a.playlist < b.playlist;
4403 struct PlaylistMapping {
4405 boost::shared_ptr<Playlist> pl;
4407 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4410 /** Remove `clicked_regionview' */
4412 Editor::remove_clicked_region ()
4414 if (clicked_routeview == 0 || clicked_regionview == 0) {
4418 begin_reversible_command (_("remove region"));
4420 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4422 playlist->clear_changes ();
4423 playlist->clear_owned_changes ();
4424 playlist->remove_region (clicked_regionview->region());
4425 if (Config->get_edit_mode() == Ripple)
4426 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4428 /* We might have removed regions, which alters other regions' layering_index,
4429 so we need to do a recursive diff here.
4431 vector<Command*> cmds;
4432 playlist->rdiff (cmds);
4433 _session->add_commands (cmds);
4435 _session->add_command(new StatefulDiffCommand (playlist));
4436 commit_reversible_command ();
4440 /** Remove the selected regions */
4442 Editor::remove_selected_regions ()
4444 RegionSelection rs = get_regions_from_selection_and_entered ();
4446 if (!_session || rs.empty()) {
4450 list<boost::shared_ptr<Region> > regions_to_remove;
4452 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4453 // we can't just remove the region(s) in this loop because
4454 // this removes them from the RegionSelection, and they thus
4455 // disappear from underneath the iterator, and the ++i above
4456 // SEGVs in a puzzling fashion.
4458 // so, first iterate over the regions to be removed from rs and
4459 // add them to the regions_to_remove list, and then
4460 // iterate over the list to actually remove them.
4462 regions_to_remove.push_back ((*i)->region());
4465 vector<boost::shared_ptr<Playlist> > playlists;
4467 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4469 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4472 // is this check necessary?
4476 /* get_regions_from_selection_and_entered() guarantees that
4477 the playlists involved are unique, so there is no need
4481 playlists.push_back (playlist);
4483 playlist->clear_changes ();
4484 playlist->clear_owned_changes ();
4485 playlist->freeze ();
4486 playlist->remove_region (*rl);
4487 if (Config->get_edit_mode() == Ripple)
4488 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4492 vector<boost::shared_ptr<Playlist> >::iterator pl;
4493 bool in_command = false;
4495 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4498 /* We might have removed regions, which alters other regions' layering_index,
4499 so we need to do a recursive diff here.
4503 begin_reversible_command (_("remove region"));
4506 vector<Command*> cmds;
4507 (*pl)->rdiff (cmds);
4508 _session->add_commands (cmds);
4510 _session->add_command(new StatefulDiffCommand (*pl));
4514 commit_reversible_command ();
4518 /** Cut, copy or clear selected regions.
4519 * @param op Operation (Cut, Copy or Clear)
4522 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4524 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4525 a map when we want ordered access to both elements. i think.
4528 vector<PlaylistMapping> pmap;
4530 framepos_t first_position = max_framepos;
4532 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4533 FreezeList freezelist;
4535 /* get ordering correct before we cut/copy */
4537 rs.sort_by_position_and_track ();
4539 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4541 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4543 if (op == Cut || op == Clear || op == Delete) {
4544 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4547 FreezeList::iterator fl;
4549 // only take state if this is a new playlist.
4550 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4556 if (fl == freezelist.end()) {
4557 pl->clear_changes();
4558 pl->clear_owned_changes ();
4560 freezelist.insert (pl);
4565 TimeAxisView* tv = &(*x)->get_time_axis_view();
4566 vector<PlaylistMapping>::iterator z;
4568 for (z = pmap.begin(); z != pmap.end(); ++z) {
4569 if ((*z).tv == tv) {
4574 if (z == pmap.end()) {
4575 pmap.push_back (PlaylistMapping (tv));
4579 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4581 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4584 /* region not yet associated with a playlist (e.g. unfinished
4591 TimeAxisView& tv = (*x)->get_time_axis_view();
4592 boost::shared_ptr<Playlist> npl;
4593 RegionSelection::iterator tmp;
4600 vector<PlaylistMapping>::iterator z;
4602 for (z = pmap.begin(); z != pmap.end(); ++z) {
4603 if ((*z).tv == &tv) {
4608 assert (z != pmap.end());
4611 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4619 boost::shared_ptr<Region> r = (*x)->region();
4620 boost::shared_ptr<Region> _xx;
4626 pl->remove_region (r);
4627 if (Config->get_edit_mode() == Ripple)
4628 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4632 _xx = RegionFactory::create (r);
4633 npl->add_region (_xx, r->position() - first_position);
4634 pl->remove_region (r);
4635 if (Config->get_edit_mode() == Ripple)
4636 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4640 /* copy region before adding, so we're not putting same object into two different playlists */
4641 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4645 pl->remove_region (r);
4646 if (Config->get_edit_mode() == Ripple)
4647 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4656 list<boost::shared_ptr<Playlist> > foo;
4658 /* the pmap is in the same order as the tracks in which selected regions occurred */
4660 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4663 foo.push_back ((*i).pl);
4668 cut_buffer->set (foo);
4672 _last_cut_copy_source_track = 0;
4674 _last_cut_copy_source_track = pmap.front().tv;
4678 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4681 /* We might have removed regions, which alters other regions' layering_index,
4682 so we need to do a recursive diff here.
4684 vector<Command*> cmds;
4685 (*pl)->rdiff (cmds);
4686 _session->add_commands (cmds);
4688 _session->add_command (new StatefulDiffCommand (*pl));
4693 Editor::cut_copy_ranges (CutCopyOp op)
4695 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4697 /* Sort the track selection now, so that it if is used, the playlists
4698 selected by the calls below to cut_copy_clear are in the order that
4699 their tracks appear in the editor. This makes things like paste
4700 of ranges work properly.
4703 sort_track_selection (ts);
4706 if (!entered_track) {
4709 ts.push_back (entered_track);
4712 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4713 (*i)->cut_copy_clear (*selection, op);
4718 Editor::paste (float times, bool from_context)
4720 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4722 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0));
4726 Editor::mouse_paste ()
4731 if (!mouse_frame (where, ignored)) {
4736 paste_internal (where, 1, get_grid_music_divisions (0));
4740 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4742 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4744 if (cut_buffer->empty(internal_editing())) {
4748 if (position == max_framepos) {
4749 position = get_preferred_edit_position();
4750 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4753 if (position == last_paste_pos) {
4754 /* repeated paste in the same position */
4757 /* paste in new location, reset repeated paste state */
4759 last_paste_pos = position;
4762 /* get everything in the correct order */
4765 if (!selection->tracks.empty()) {
4766 /* If there is a track selection, paste into exactly those tracks and
4767 only those tracks. This allows the user to be explicit and override
4768 the below "do the reasonable thing" logic. */
4769 ts = selection->tracks.filter_to_unique_playlists ();
4770 sort_track_selection (ts);
4772 /* Figure out which track to base the paste at. */
4773 TimeAxisView* base_track = NULL;
4774 if (_edit_point == Editing::EditAtMouse && entered_track) {
4775 /* With the mouse edit point, paste onto the track under the mouse. */
4776 base_track = entered_track;
4777 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4778 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4779 base_track = &entered_regionview->get_time_axis_view();
4780 } else if (_last_cut_copy_source_track) {
4781 /* Paste to the track that the cut/copy came from (see mantis #333). */
4782 base_track = _last_cut_copy_source_track;
4784 /* This is "impossible" since we've copied... well, do nothing. */
4788 /* Walk up to parent if necessary, so base track is a route. */
4789 while (base_track->get_parent()) {
4790 base_track = base_track->get_parent();
4793 /* Add base track and all tracks below it. The paste logic will select
4794 the appropriate object types from the cut buffer in relative order. */
4795 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4796 if ((*i)->order() >= base_track->order()) {
4801 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4802 sort_track_selection (ts);
4804 /* Add automation children of each track in order, for pasting several lines. */
4805 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4806 /* Add any automation children for pasting several lines */
4807 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4812 typedef RouteTimeAxisView::AutomationTracks ATracks;
4813 const ATracks& atracks = rtv->automation_tracks();
4814 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4815 i = ts.insert(i, a->second.get());
4820 /* We now have a list of trackviews starting at base_track, including
4821 automation children, in the order shown in the editor, e.g. R1,
4822 R1.A1, R1.A2, R2, R2.A1, ... */
4825 begin_reversible_command (Operations::paste);
4827 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4828 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4829 /* Only one line copied, and one automation track selected. Do a
4830 "greedy" paste from one automation type to another. */
4832 PasteContext ctx(paste_count, times, ItemCounts(), true);
4833 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4837 /* Paste into tracks */
4839 PasteContext ctx(paste_count, times, ItemCounts(), false);
4840 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4841 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4845 commit_reversible_command ();
4849 Editor::duplicate_regions (float times)
4851 RegionSelection rs (get_regions_from_selection_and_entered());
4852 duplicate_some_regions (rs, times);
4856 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4858 if (regions.empty ()) {
4862 boost::shared_ptr<Playlist> playlist;
4863 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4864 RegionSelection foo;
4866 framepos_t const start_frame = regions.start ();
4867 framepos_t const end_frame = regions.end_frame ();
4868 framecnt_t const gap = end_frame - start_frame + 1;
4870 begin_reversible_command (Operations::duplicate_region);
4872 selection->clear_regions ();
4874 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4876 boost::shared_ptr<Region> r ((*i)->region());
4878 TimeAxisView& tv = (*i)->get_time_axis_view();
4879 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4880 latest_regionviews.clear ();
4881 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4883 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4884 playlist = (*i)->region()->playlist();
4885 playlist->clear_changes ();
4886 playlist->duplicate (r, position, gap, times);
4887 _session->add_command(new StatefulDiffCommand (playlist));
4891 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4895 selection->set (foo);
4898 commit_reversible_command ();
4902 Editor::duplicate_selection (float times)
4904 if (selection->time.empty() || selection->tracks.empty()) {
4908 boost::shared_ptr<Playlist> playlist;
4910 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4912 bool in_command = false;
4914 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4915 if ((playlist = (*i)->playlist()) == 0) {
4918 playlist->clear_changes ();
4920 if (clicked_selection) {
4921 playlist->duplicate_range (selection->time[clicked_selection], times);
4923 playlist->duplicate_ranges (selection->time, times);
4927 begin_reversible_command (_("duplicate range selection"));
4930 _session->add_command (new StatefulDiffCommand (playlist));
4935 // now "move" range selection to after the current range selection
4936 framecnt_t distance = 0;
4938 if (clicked_selection) {
4939 distance = selection->time[clicked_selection].end -
4940 selection->time[clicked_selection].start;
4942 distance = selection->time.end_frame() - selection->time.start();
4945 selection->move_time (distance);
4947 commit_reversible_command ();
4951 /** Reset all selected points to the relevant default value */
4953 Editor::reset_point_selection ()
4955 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4956 ARDOUR::AutomationList::iterator j = (*i)->model ();
4957 (*j)->value = (*i)->line().the_list()->default_value ();
4962 Editor::center_playhead ()
4964 float const page = _visible_canvas_width * samples_per_pixel;
4965 center_screen_internal (playhead_cursor->current_frame (), page);
4969 Editor::center_edit_point ()
4971 float const page = _visible_canvas_width * samples_per_pixel;
4972 center_screen_internal (get_preferred_edit_position(), page);
4975 /** Caller must begin and commit a reversible command */
4977 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4979 playlist->clear_changes ();
4981 _session->add_command (new StatefulDiffCommand (playlist));
4985 Editor::nudge_track (bool use_edit, bool forwards)
4987 boost::shared_ptr<Playlist> playlist;
4988 framepos_t distance;
4989 framepos_t next_distance;
4993 start = get_preferred_edit_position();
4998 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
5002 if (selection->tracks.empty()) {
5006 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5007 bool in_command = false;
5009 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5011 if ((playlist = (*i)->playlist()) == 0) {
5015 playlist->clear_changes ();
5016 playlist->clear_owned_changes ();
5018 playlist->nudge_after (start, distance, forwards);
5021 begin_reversible_command (_("nudge track"));
5024 vector<Command*> cmds;
5026 playlist->rdiff (cmds);
5027 _session->add_commands (cmds);
5029 _session->add_command (new StatefulDiffCommand (playlist));
5033 commit_reversible_command ();
5038 Editor::remove_last_capture ()
5040 vector<string> choices;
5047 if (Config->get_verify_remove_last_capture()) {
5048 prompt = _("Do you really want to destroy the last capture?"
5049 "\n(This is destructive and cannot be undone)");
5051 choices.push_back (_("No, do nothing."));
5052 choices.push_back (_("Yes, destroy it."));
5054 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
5056 if (prompter.run () == 1) {
5057 _session->remove_last_capture ();
5058 _regions->redisplay ();
5062 _session->remove_last_capture();
5063 _regions->redisplay ();
5068 Editor::normalize_region ()
5074 RegionSelection rs = get_regions_from_selection_and_entered ();
5080 NormalizeDialog dialog (rs.size() > 1);
5082 if (dialog.run () != RESPONSE_ACCEPT) {
5086 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5089 /* XXX: should really only count audio regions here */
5090 int const regions = rs.size ();
5092 /* Make a list of the selected audio regions' maximum amplitudes, and also
5093 obtain the maximum amplitude of them all.
5095 list<double> max_amps;
5096 list<double> rms_vals;
5099 bool use_rms = dialog.constrain_rms ();
5101 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5102 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5106 dialog.descend (1.0 / regions);
5107 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5109 double r = arv->audio_region()->rms (&dialog);
5110 max_rms = max (max_rms, r);
5111 rms_vals.push_back (r);
5115 /* the user cancelled the operation */
5119 max_amps.push_back (a);
5120 max_amp = max (max_amp, a);
5124 list<double>::const_iterator a = max_amps.begin ();
5125 list<double>::const_iterator l = rms_vals.begin ();
5126 bool in_command = false;
5128 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5129 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5134 arv->region()->clear_changes ();
5136 double amp = dialog.normalize_individually() ? *a : max_amp;
5137 double target = dialog.target_peak (); // dB
5140 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5141 const double t_rms = dialog.target_rms ();
5142 const gain_t c_peak = dB_to_coefficient (target);
5143 const gain_t c_rms = dB_to_coefficient (t_rms);
5144 if ((amp_rms / c_rms) > (amp / c_peak)) {
5150 arv->audio_region()->normalize (amp, target);
5153 begin_reversible_command (_("normalize"));
5156 _session->add_command (new StatefulDiffCommand (arv->region()));
5163 commit_reversible_command ();
5169 Editor::reset_region_scale_amplitude ()
5175 RegionSelection rs = get_regions_from_selection_and_entered ();
5181 bool in_command = false;
5183 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5184 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5187 arv->region()->clear_changes ();
5188 arv->audio_region()->set_scale_amplitude (1.0f);
5191 begin_reversible_command ("reset gain");
5194 _session->add_command (new StatefulDiffCommand (arv->region()));
5198 commit_reversible_command ();
5203 Editor::adjust_region_gain (bool up)
5205 RegionSelection rs = get_regions_from_selection_and_entered ();
5207 if (!_session || rs.empty()) {
5211 bool in_command = false;
5213 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5214 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5219 arv->region()->clear_changes ();
5221 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5229 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5232 begin_reversible_command ("adjust region gain");
5235 _session->add_command (new StatefulDiffCommand (arv->region()));
5239 commit_reversible_command ();
5245 Editor::reverse_region ()
5251 Reverse rev (*_session);
5252 apply_filter (rev, _("reverse regions"));
5256 Editor::strip_region_silence ()
5262 RegionSelection rs = get_regions_from_selection_and_entered ();
5268 std::list<RegionView*> audio_only;
5270 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5271 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5273 audio_only.push_back (arv);
5277 assert (!audio_only.empty());
5279 StripSilenceDialog d (_session, audio_only);
5280 int const r = d.run ();
5284 if (r == Gtk::RESPONSE_OK) {
5285 ARDOUR::AudioIntervalMap silences;
5286 d.silences (silences);
5287 StripSilence s (*_session, silences, d.fade_length());
5289 apply_filter (s, _("strip silence"), &d);
5294 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5296 Evoral::Sequence<Evoral::Beats>::Notes selected;
5297 mrv.selection_as_notelist (selected, true);
5299 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5300 v.push_back (selected);
5302 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5304 return op (mrv.midi_region()->model(), pos_beats, v);
5308 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5314 bool in_command = false;
5316 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5317 RegionSelection::const_iterator tmp = r;
5320 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5323 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5326 begin_reversible_command (op.name ());
5330 _session->add_command (cmd);
5338 commit_reversible_command ();
5343 Editor::fork_region ()
5345 RegionSelection rs = get_regions_from_selection_and_entered ();
5351 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5352 bool in_command = false;
5356 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5357 RegionSelection::iterator tmp = r;
5360 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5364 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5365 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5366 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5369 begin_reversible_command (_("Fork Region(s)"));
5372 playlist->clear_changes ();
5373 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5374 _session->add_command(new StatefulDiffCommand (playlist));
5376 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5384 commit_reversible_command ();
5389 Editor::quantize_region ()
5392 quantize_regions(get_regions_from_selection_and_entered ());
5397 Editor::quantize_regions (const RegionSelection& rs)
5399 if (rs.n_midi_regions() == 0) {
5403 if (!quantize_dialog) {
5404 quantize_dialog = new QuantizeDialog (*this);
5407 if (quantize_dialog->is_mapped()) {
5408 /* in progress already */
5412 quantize_dialog->present ();
5413 const int r = quantize_dialog->run ();
5414 quantize_dialog->hide ();
5416 if (r == Gtk::RESPONSE_OK) {
5417 Quantize quant (quantize_dialog->snap_start(),
5418 quantize_dialog->snap_end(),
5419 quantize_dialog->start_grid_size(),
5420 quantize_dialog->end_grid_size(),
5421 quantize_dialog->strength(),
5422 quantize_dialog->swing(),
5423 quantize_dialog->threshold());
5425 apply_midi_note_edit_op (quant, rs);
5430 Editor::legatize_region (bool shrink_only)
5433 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5438 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5440 if (rs.n_midi_regions() == 0) {
5444 Legatize legatize(shrink_only);
5445 apply_midi_note_edit_op (legatize, rs);
5449 Editor::transform_region ()
5452 transform_regions(get_regions_from_selection_and_entered ());
5457 Editor::transform_regions (const RegionSelection& rs)
5459 if (rs.n_midi_regions() == 0) {
5466 const int r = td.run();
5469 if (r == Gtk::RESPONSE_OK) {
5470 Transform transform(td.get());
5471 apply_midi_note_edit_op(transform, rs);
5476 Editor::transpose_region ()
5479 transpose_regions(get_regions_from_selection_and_entered ());
5484 Editor::transpose_regions (const RegionSelection& rs)
5486 if (rs.n_midi_regions() == 0) {
5491 int const r = d.run ();
5493 if (r == RESPONSE_ACCEPT) {
5494 Transpose transpose(d.semitones ());
5495 apply_midi_note_edit_op (transpose, rs);
5500 Editor::insert_patch_change (bool from_context)
5502 RegionSelection rs = get_regions_from_selection_and_entered ();
5508 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5510 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5511 there may be more than one, but the PatchChangeDialog can only offer
5512 one set of patch menus.
5514 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5516 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5517 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5519 if (d.run() == RESPONSE_CANCEL) {
5523 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5524 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5526 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5527 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5534 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5536 RegionSelection rs = get_regions_from_selection_and_entered ();
5542 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5543 bool in_command = false;
5548 int const N = rs.size ();
5550 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5551 RegionSelection::iterator tmp = r;
5554 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5556 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5559 progress->descend (1.0 / N);
5562 if (arv->audio_region()->apply (filter, progress) == 0) {
5564 playlist->clear_changes ();
5565 playlist->clear_owned_changes ();
5568 begin_reversible_command (command);
5572 if (filter.results.empty ()) {
5574 /* no regions returned; remove the old one */
5575 playlist->remove_region (arv->region ());
5579 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5581 /* first region replaces the old one */
5582 playlist->replace_region (arv->region(), *res, (*res)->position());
5586 while (res != filter.results.end()) {
5587 playlist->add_region (*res, (*res)->position());
5593 /* We might have removed regions, which alters other regions' layering_index,
5594 so we need to do a recursive diff here.
5596 vector<Command*> cmds;
5597 playlist->rdiff (cmds);
5598 _session->add_commands (cmds);
5600 _session->add_command(new StatefulDiffCommand (playlist));
5604 progress->ascend ();
5613 commit_reversible_command ();
5618 Editor::external_edit_region ()
5624 Editor::reset_region_gain_envelopes ()
5626 RegionSelection rs = get_regions_from_selection_and_entered ();
5628 if (!_session || rs.empty()) {
5632 bool in_command = false;
5634 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5635 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5637 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5638 XMLNode& before (alist->get_state());
5640 arv->audio_region()->set_default_envelope ();
5643 begin_reversible_command (_("reset region gain"));
5646 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5651 commit_reversible_command ();
5656 Editor::set_region_gain_visibility (RegionView* rv)
5658 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5660 arv->update_envelope_visibility();
5665 Editor::set_gain_envelope_visibility ()
5671 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5672 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5674 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5680 Editor::toggle_gain_envelope_active ()
5682 if (_ignore_region_action) {
5686 RegionSelection rs = get_regions_from_selection_and_entered ();
5688 if (!_session || rs.empty()) {
5692 bool in_command = false;
5694 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5695 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5697 arv->region()->clear_changes ();
5698 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5701 begin_reversible_command (_("region gain envelope active"));
5704 _session->add_command (new StatefulDiffCommand (arv->region()));
5709 commit_reversible_command ();
5714 Editor::toggle_region_lock ()
5716 if (_ignore_region_action) {
5720 RegionSelection rs = get_regions_from_selection_and_entered ();
5722 if (!_session || rs.empty()) {
5726 begin_reversible_command (_("toggle region lock"));
5728 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5729 (*i)->region()->clear_changes ();
5730 (*i)->region()->set_locked (!(*i)->region()->locked());
5731 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5734 commit_reversible_command ();
5738 Editor::toggle_region_video_lock ()
5740 if (_ignore_region_action) {
5744 RegionSelection rs = get_regions_from_selection_and_entered ();
5746 if (!_session || rs.empty()) {
5750 begin_reversible_command (_("Toggle Video Lock"));
5752 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5753 (*i)->region()->clear_changes ();
5754 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5755 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5758 commit_reversible_command ();
5762 Editor::toggle_region_lock_style ()
5764 if (_ignore_region_action) {
5768 RegionSelection rs = get_regions_from_selection_and_entered ();
5770 if (!_session || rs.empty()) {
5774 begin_reversible_command (_("region lock style"));
5776 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5777 (*i)->region()->clear_changes ();
5778 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5779 (*i)->region()->set_position_lock_style (ns);
5780 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5783 commit_reversible_command ();
5787 Editor::toggle_opaque_region ()
5789 if (_ignore_region_action) {
5793 RegionSelection rs = get_regions_from_selection_and_entered ();
5795 if (!_session || rs.empty()) {
5799 begin_reversible_command (_("change region opacity"));
5801 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5802 (*i)->region()->clear_changes ();
5803 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5804 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5807 commit_reversible_command ();
5811 Editor::toggle_record_enable ()
5813 bool new_state = false;
5815 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5816 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5819 if (!rtav->is_track())
5823 new_state = !rtav->track()->rec_enable_control()->get_value();
5827 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5832 Editor::toggle_solo ()
5834 bool new_state = false;
5836 boost::shared_ptr<ControlList> cl (new ControlList);
5838 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5839 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5846 new_state = !rtav->route()->soloed ();
5850 cl->push_back (rtav->route()->solo_control());
5853 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5857 Editor::toggle_mute ()
5859 bool new_state = false;
5861 boost::shared_ptr<RouteList> rl (new RouteList);
5863 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5864 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5871 new_state = !rtav->route()->muted();
5875 rl->push_back (rtav->route());
5878 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5882 Editor::toggle_solo_isolate ()
5888 Editor::fade_range ()
5890 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5892 begin_reversible_command (_("fade range"));
5894 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5895 (*i)->fade_range (selection->time);
5898 commit_reversible_command ();
5903 Editor::set_fade_length (bool in)
5905 RegionSelection rs = get_regions_from_selection_and_entered ();
5911 /* we need a region to measure the offset from the start */
5913 RegionView* rv = rs.front ();
5915 framepos_t pos = get_preferred_edit_position();
5919 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5920 /* edit point is outside the relevant region */
5925 if (pos <= rv->region()->position()) {
5929 len = pos - rv->region()->position();
5930 cmd = _("set fade in length");
5932 if (pos >= rv->region()->last_frame()) {
5936 len = rv->region()->last_frame() - pos;
5937 cmd = _("set fade out length");
5940 bool in_command = false;
5942 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5943 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5949 boost::shared_ptr<AutomationList> alist;
5951 alist = tmp->audio_region()->fade_in();
5953 alist = tmp->audio_region()->fade_out();
5956 XMLNode &before = alist->get_state();
5959 tmp->audio_region()->set_fade_in_length (len);
5960 tmp->audio_region()->set_fade_in_active (true);
5962 tmp->audio_region()->set_fade_out_length (len);
5963 tmp->audio_region()->set_fade_out_active (true);
5967 begin_reversible_command (cmd);
5970 XMLNode &after = alist->get_state();
5971 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5975 commit_reversible_command ();
5980 Editor::set_fade_in_shape (FadeShape shape)
5982 RegionSelection rs = get_regions_from_selection_and_entered ();
5987 bool in_command = false;
5989 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5990 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5996 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5997 XMLNode &before = alist->get_state();
5999 tmp->audio_region()->set_fade_in_shape (shape);
6002 begin_reversible_command (_("set fade in shape"));
6005 XMLNode &after = alist->get_state();
6006 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6010 commit_reversible_command ();
6015 Editor::set_fade_out_shape (FadeShape shape)
6017 RegionSelection rs = get_regions_from_selection_and_entered ();
6022 bool in_command = false;
6024 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6025 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6031 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6032 XMLNode &before = alist->get_state();
6034 tmp->audio_region()->set_fade_out_shape (shape);
6037 begin_reversible_command (_("set fade out shape"));
6040 XMLNode &after = alist->get_state();
6041 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6045 commit_reversible_command ();
6050 Editor::set_fade_in_active (bool yn)
6052 RegionSelection rs = get_regions_from_selection_and_entered ();
6057 bool in_command = false;
6059 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6060 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6067 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6069 ar->clear_changes ();
6070 ar->set_fade_in_active (yn);
6073 begin_reversible_command (_("set fade in active"));
6076 _session->add_command (new StatefulDiffCommand (ar));
6080 commit_reversible_command ();
6085 Editor::set_fade_out_active (bool yn)
6087 RegionSelection rs = get_regions_from_selection_and_entered ();
6092 bool in_command = false;
6094 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6095 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6101 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6103 ar->clear_changes ();
6104 ar->set_fade_out_active (yn);
6107 begin_reversible_command (_("set fade out active"));
6110 _session->add_command(new StatefulDiffCommand (ar));
6114 commit_reversible_command ();
6119 Editor::toggle_region_fades (int dir)
6121 if (_ignore_region_action) {
6125 boost::shared_ptr<AudioRegion> ar;
6128 RegionSelection rs = get_regions_from_selection_and_entered ();
6134 RegionSelection::iterator i;
6135 for (i = rs.begin(); i != rs.end(); ++i) {
6136 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6138 yn = ar->fade_out_active ();
6140 yn = ar->fade_in_active ();
6146 if (i == rs.end()) {
6150 /* XXX should this undo-able? */
6151 bool in_command = false;
6153 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6154 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6157 ar->clear_changes ();
6159 if (dir == 1 || dir == 0) {
6160 ar->set_fade_in_active (!yn);
6163 if (dir == -1 || dir == 0) {
6164 ar->set_fade_out_active (!yn);
6167 begin_reversible_command (_("toggle fade active"));
6170 _session->add_command(new StatefulDiffCommand (ar));
6174 commit_reversible_command ();
6179 /** Update region fade visibility after its configuration has been changed */
6181 Editor::update_region_fade_visibility ()
6183 bool _fade_visibility = _session->config.get_show_region_fades ();
6185 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6186 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6188 if (_fade_visibility) {
6189 v->audio_view()->show_all_fades ();
6191 v->audio_view()->hide_all_fades ();
6198 Editor::set_edit_point ()
6203 if (!mouse_frame (where, ignored)) {
6209 if (selection->markers.empty()) {
6211 mouse_add_new_marker (where);
6216 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6219 loc->move_to (where);
6225 Editor::set_playhead_cursor ()
6227 if (entered_marker) {
6228 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6233 if (!mouse_frame (where, ignored)) {
6240 _session->request_locate (where, _session->transport_rolling());
6244 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6245 cancel_time_selection();
6250 Editor::split_region ()
6252 if (_drags->active ()) {
6256 //if a range is selected, separate it
6257 if ( !selection->time.empty()) {
6258 separate_regions_between (selection->time);
6262 //if no range was selected, try to find some regions to split
6263 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6265 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6267 framepos_t where = get_preferred_edit_position ();
6273 if (snap_musical()) {
6274 split_regions_at (where, rs, get_grid_music_divisions (0));
6276 split_regions_at (where, rs, 0);
6282 Editor::select_next_route()
6284 if (selection->tracks.empty()) {
6285 selection->set (track_views.front());
6289 TimeAxisView* current = selection->tracks.front();
6293 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6295 if (*i == current) {
6297 if (i != track_views.end()) {
6300 current = (*(track_views.begin()));
6301 //selection->set (*(track_views.begin()));
6307 rui = dynamic_cast<RouteUI *>(current);
6309 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6311 selection->set (current);
6313 ensure_time_axis_view_is_visible (*current, false);
6317 Editor::select_prev_route()
6319 if (selection->tracks.empty()) {
6320 selection->set (track_views.front());
6324 TimeAxisView* current = selection->tracks.front();
6328 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6330 if (*i == current) {
6332 if (i != track_views.rend()) {
6335 current = *(track_views.rbegin());
6340 rui = dynamic_cast<RouteUI *>(current);
6342 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6344 selection->set (current);
6346 ensure_time_axis_view_is_visible (*current, false);
6350 Editor::set_loop_from_selection (bool play)
6352 if (_session == 0) {
6356 framepos_t start, end;
6357 if (!get_selection_extents ( start, end))
6360 set_loop_range (start, end, _("set loop range from selection"));
6363 _session->request_play_loop (true, true);
6368 Editor::set_loop_from_region (bool play)
6370 framepos_t start, end;
6371 if (!get_selection_extents ( start, end))
6374 set_loop_range (start, end, _("set loop range from region"));
6377 _session->request_locate (start, true);
6378 _session->request_play_loop (true);
6383 Editor::set_punch_from_selection ()
6385 if (_session == 0) {
6389 framepos_t start, end;
6390 if (!get_selection_extents ( start, end))
6393 set_punch_range (start, end, _("set punch range from selection"));
6397 Editor::set_auto_punch_range ()
6399 // auto punch in/out button from a single button
6400 // If Punch In is unset, set punch range from playhead to end, enable punch in
6401 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6402 // rewound beyond the Punch In marker, in which case that marker will be moved back
6403 // to the current playhead position.
6404 // If punch out is set, it clears the punch range and Punch In/Out buttons
6406 if (_session == 0) {
6410 Location* tpl = transport_punch_location();
6411 framepos_t now = playhead_cursor->current_frame();
6412 framepos_t begin = now;
6413 framepos_t end = _session->current_end_frame();
6415 if (!_session->config.get_punch_in()) {
6416 // First Press - set punch in and create range from here to eternity
6417 set_punch_range (begin, end, _("Auto Punch In"));
6418 _session->config.set_punch_in(true);
6419 } else if (tpl && !_session->config.get_punch_out()) {
6420 // Second press - update end range marker and set punch_out
6421 if (now < tpl->start()) {
6422 // playhead has been rewound - move start back and pretend nothing happened
6424 set_punch_range (begin, end, _("Auto Punch In/Out"));
6426 // normal case for 2nd press - set the punch out
6427 end = playhead_cursor->current_frame ();
6428 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6429 _session->config.set_punch_out(true);
6432 if (_session->config.get_punch_out()) {
6433 _session->config.set_punch_out(false);
6436 if (_session->config.get_punch_in()) {
6437 _session->config.set_punch_in(false);
6442 // third press - unset punch in/out and remove range
6443 _session->locations()->remove(tpl);
6450 Editor::set_session_extents_from_selection ()
6452 if (_session == 0) {
6456 framepos_t start, end;
6457 if (!get_selection_extents ( start, end))
6461 if ((loc = _session->locations()->session_range_location()) == 0) {
6462 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6464 XMLNode &before = loc->get_state();
6466 _session->set_session_extents (start, end);
6468 XMLNode &after = loc->get_state();
6470 begin_reversible_command (_("set session start/end from selection"));
6472 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6474 commit_reversible_command ();
6477 _session->set_end_is_free (false);
6481 Editor::set_punch_start_from_edit_point ()
6485 framepos_t start = 0;
6486 framepos_t end = max_framepos;
6488 //use the existing punch end, if any
6489 Location* tpl = transport_punch_location();
6494 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6495 start = _session->audible_frame();
6497 start = get_preferred_edit_position();
6500 //snap the selection start/end
6503 //if there's not already a sensible selection endpoint, go "forever"
6504 if ( start > end ) {
6508 set_punch_range (start, end, _("set punch start from EP"));
6514 Editor::set_punch_end_from_edit_point ()
6518 framepos_t start = 0;
6519 framepos_t end = max_framepos;
6521 //use the existing punch start, if any
6522 Location* tpl = transport_punch_location();
6524 start = tpl->start();
6527 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6528 end = _session->audible_frame();
6530 end = get_preferred_edit_position();
6533 //snap the selection start/end
6536 set_punch_range (start, end, _("set punch end from EP"));
6542 Editor::set_loop_start_from_edit_point ()
6546 framepos_t start = 0;
6547 framepos_t end = max_framepos;
6549 //use the existing loop end, if any
6550 Location* tpl = transport_loop_location();
6555 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6556 start = _session->audible_frame();
6558 start = get_preferred_edit_position();
6561 //snap the selection start/end
6564 //if there's not already a sensible selection endpoint, go "forever"
6565 if ( start > end ) {
6569 set_loop_range (start, end, _("set loop start from EP"));
6575 Editor::set_loop_end_from_edit_point ()
6579 framepos_t start = 0;
6580 framepos_t end = max_framepos;
6582 //use the existing loop start, if any
6583 Location* tpl = transport_loop_location();
6585 start = tpl->start();
6588 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6589 end = _session->audible_frame();
6591 end = get_preferred_edit_position();
6594 //snap the selection start/end
6597 set_loop_range (start, end, _("set loop end from EP"));
6602 Editor::set_punch_from_region ()
6604 framepos_t start, end;
6605 if (!get_selection_extents ( start, end))
6608 set_punch_range (start, end, _("set punch range from region"));
6612 Editor::pitch_shift_region ()
6614 RegionSelection rs = get_regions_from_selection_and_entered ();
6616 RegionSelection audio_rs;
6617 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6618 if (dynamic_cast<AudioRegionView*> (*i)) {
6619 audio_rs.push_back (*i);
6623 if (audio_rs.empty()) {
6627 pitch_shift (audio_rs, 1.2);
6631 Editor::set_tempo_from_region ()
6633 RegionSelection rs = get_regions_from_selection_and_entered ();
6635 if (!_session || rs.empty()) {
6639 RegionView* rv = rs.front();
6641 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6645 Editor::use_range_as_bar ()
6647 framepos_t start, end;
6648 if (get_edit_op_range (start, end)) {
6649 define_one_bar (start, end);
6654 Editor::define_one_bar (framepos_t start, framepos_t end)
6656 framepos_t length = end - start;
6658 const Meter& m (_session->tempo_map().meter_at_frame (start));
6660 /* length = 1 bar */
6662 /* We're going to deliver a constant tempo here,
6663 so we can use frames per beat to determine length.
6664 now we want frames per beat.
6665 we have frames per bar, and beats per bar, so ...
6668 /* XXXX METER MATH */
6670 double frames_per_beat = length / m.divisions_per_bar();
6672 /* beats per minute = */
6674 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6676 /* now decide whether to:
6678 (a) set global tempo
6679 (b) add a new tempo marker
6683 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6685 bool do_global = false;
6687 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6689 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6690 at the start, or create a new marker
6693 vector<string> options;
6694 options.push_back (_("Cancel"));
6695 options.push_back (_("Add new marker"));
6696 options.push_back (_("Set global tempo"));
6699 _("Define one bar"),
6700 _("Do you want to set the global tempo or add a new tempo marker?"),
6704 c.set_default_response (2);
6720 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6721 if the marker is at the region starter, change it, otherwise add
6726 begin_reversible_command (_("set tempo from region"));
6727 XMLNode& before (_session->tempo_map().get_state());
6730 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6731 } else if (t.frame() == start) {
6732 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6734 const Tempo tempo (beats_per_minute, t.note_type());
6735 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6738 XMLNode& after (_session->tempo_map().get_state());
6740 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6741 commit_reversible_command ();
6745 Editor::split_region_at_transients ()
6747 AnalysisFeatureList positions;
6749 RegionSelection rs = get_regions_from_selection_and_entered ();
6751 if (!_session || rs.empty()) {
6755 begin_reversible_command (_("split regions"));
6757 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6759 RegionSelection::iterator tmp;
6764 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6767 ar->transients (positions);
6768 split_region_at_points ((*i)->region(), positions, true);
6775 commit_reversible_command ();
6780 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6782 bool use_rhythmic_rodent = false;
6784 boost::shared_ptr<Playlist> pl = r->playlist();
6786 list<boost::shared_ptr<Region> > new_regions;
6792 if (positions.empty()) {
6796 if (positions.size() > 20 && can_ferret) {
6797 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);
6798 MessageDialog msg (msgstr,
6801 Gtk::BUTTONS_OK_CANCEL);
6804 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6805 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6807 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6810 msg.set_title (_("Excessive split?"));
6813 int response = msg.run();
6819 case RESPONSE_APPLY:
6820 use_rhythmic_rodent = true;
6827 if (use_rhythmic_rodent) {
6828 show_rhythm_ferret ();
6832 AnalysisFeatureList::const_iterator x;
6834 pl->clear_changes ();
6835 pl->clear_owned_changes ();
6837 x = positions.begin();
6839 if (x == positions.end()) {
6844 pl->remove_region (r);
6848 framepos_t rstart = r->first_frame ();
6849 framepos_t rend = r->last_frame ();
6851 while (x != positions.end()) {
6853 /* deal with positons that are out of scope of present region bounds */
6854 if (*x <= rstart || *x > rend) {
6859 /* file start = original start + how far we from the initial position ? */
6861 framepos_t file_start = r->start() + pos;
6863 /* length = next position - current position */
6865 framepos_t len = (*x) - pos - rstart;
6867 /* XXX we do we really want to allow even single-sample regions?
6868 * shouldn't we have some kind of lower limit on region size?
6877 if (RegionFactory::region_name (new_name, r->name())) {
6881 /* do NOT announce new regions 1 by one, just wait till they are all done */
6885 plist.add (ARDOUR::Properties::start, file_start);
6886 plist.add (ARDOUR::Properties::length, len);
6887 plist.add (ARDOUR::Properties::name, new_name);
6888 plist.add (ARDOUR::Properties::layer, 0);
6889 // TODO set transients_offset
6891 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6892 /* because we set annouce to false, manually add the new region to the
6895 RegionFactory::map_add (nr);
6897 pl->add_region (nr, rstart + pos);
6900 new_regions.push_front(nr);
6909 RegionFactory::region_name (new_name, r->name());
6911 /* Add the final region */
6914 plist.add (ARDOUR::Properties::start, r->start() + pos);
6915 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6916 plist.add (ARDOUR::Properties::name, new_name);
6917 plist.add (ARDOUR::Properties::layer, 0);
6919 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6920 /* because we set annouce to false, manually add the new region to the
6923 RegionFactory::map_add (nr);
6924 pl->add_region (nr, r->position() + pos);
6927 new_regions.push_front(nr);
6932 /* We might have removed regions, which alters other regions' layering_index,
6933 so we need to do a recursive diff here.
6935 vector<Command*> cmds;
6937 _session->add_commands (cmds);
6939 _session->add_command (new StatefulDiffCommand (pl));
6943 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6944 set_selected_regionview_from_region_list ((*i), Selection::Add);
6950 Editor::place_transient()
6956 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6962 framepos_t where = get_preferred_edit_position();
6964 begin_reversible_command (_("place transient"));
6966 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6967 (*r)->region()->add_transient(where);
6970 commit_reversible_command ();
6974 Editor::remove_transient(ArdourCanvas::Item* item)
6980 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6983 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6984 _arv->remove_transient (*(float*) _line->get_data ("position"));
6988 Editor::snap_regions_to_grid ()
6990 list <boost::shared_ptr<Playlist > > used_playlists;
6992 RegionSelection rs = get_regions_from_selection_and_entered ();
6994 if (!_session || rs.empty()) {
6998 begin_reversible_command (_("snap regions to grid"));
7000 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7002 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7004 if (!pl->frozen()) {
7005 /* we haven't seen this playlist before */
7007 /* remember used playlists so we can thaw them later */
7008 used_playlists.push_back(pl);
7012 framepos_t start_frame = (*r)->region()->first_frame ();
7013 snap_to (start_frame);
7014 (*r)->region()->set_position (start_frame);
7017 while (used_playlists.size() > 0) {
7018 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7020 used_playlists.pop_front();
7023 commit_reversible_command ();
7027 Editor::close_region_gaps ()
7029 list <boost::shared_ptr<Playlist > > used_playlists;
7031 RegionSelection rs = get_regions_from_selection_and_entered ();
7033 if (!_session || rs.empty()) {
7037 Dialog dialog (_("Close Region Gaps"));
7040 table.set_spacings (12);
7041 table.set_border_width (12);
7042 Label* l = manage (left_aligned_label (_("Crossfade length")));
7043 table.attach (*l, 0, 1, 0, 1);
7045 SpinButton spin_crossfade (1, 0);
7046 spin_crossfade.set_range (0, 15);
7047 spin_crossfade.set_increments (1, 1);
7048 spin_crossfade.set_value (5);
7049 table.attach (spin_crossfade, 1, 2, 0, 1);
7051 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7053 l = manage (left_aligned_label (_("Pull-back length")));
7054 table.attach (*l, 0, 1, 1, 2);
7056 SpinButton spin_pullback (1, 0);
7057 spin_pullback.set_range (0, 100);
7058 spin_pullback.set_increments (1, 1);
7059 spin_pullback.set_value(30);
7060 table.attach (spin_pullback, 1, 2, 1, 2);
7062 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7064 dialog.get_vbox()->pack_start (table);
7065 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7066 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7069 if (dialog.run () == RESPONSE_CANCEL) {
7073 framepos_t crossfade_len = spin_crossfade.get_value();
7074 framepos_t pull_back_frames = spin_pullback.get_value();
7076 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7077 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7079 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7081 begin_reversible_command (_("close region gaps"));
7084 boost::shared_ptr<Region> last_region;
7086 rs.sort_by_position_and_track();
7088 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7090 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7092 if (!pl->frozen()) {
7093 /* we haven't seen this playlist before */
7095 /* remember used playlists so we can thaw them later */
7096 used_playlists.push_back(pl);
7100 framepos_t position = (*r)->region()->position();
7102 if (idx == 0 || position < last_region->position()){
7103 last_region = (*r)->region();
7108 (*r)->region()->trim_front( (position - pull_back_frames));
7109 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7111 last_region = (*r)->region();
7116 while (used_playlists.size() > 0) {
7117 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7119 used_playlists.pop_front();
7122 commit_reversible_command ();
7126 Editor::tab_to_transient (bool forward)
7128 AnalysisFeatureList positions;
7130 RegionSelection rs = get_regions_from_selection_and_entered ();
7136 framepos_t pos = _session->audible_frame ();
7138 if (!selection->tracks.empty()) {
7140 /* don't waste time searching for transients in duplicate playlists.
7143 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7145 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7147 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7150 boost::shared_ptr<Track> tr = rtv->track();
7152 boost::shared_ptr<Playlist> pl = tr->playlist ();
7154 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7157 positions.push_back (result);
7170 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7171 (*r)->region()->get_transients (positions);
7175 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7178 AnalysisFeatureList::iterator x;
7180 for (x = positions.begin(); x != positions.end(); ++x) {
7186 if (x != positions.end ()) {
7187 _session->request_locate (*x);
7191 AnalysisFeatureList::reverse_iterator x;
7193 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7199 if (x != positions.rend ()) {
7200 _session->request_locate (*x);
7206 Editor::playhead_forward_to_grid ()
7212 framepos_t pos = playhead_cursor->current_frame ();
7213 if (pos < max_framepos - 1) {
7215 snap_to_internal (pos, RoundUpAlways, false);
7216 _session->request_locate (pos);
7222 Editor::playhead_backward_to_grid ()
7228 framepos_t pos = playhead_cursor->current_frame ();
7231 snap_to_internal (pos, RoundDownAlways, false);
7232 _session->request_locate (pos);
7237 Editor::set_track_height (Height h)
7239 TrackSelection& ts (selection->tracks);
7241 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7242 (*x)->set_height_enum (h);
7247 Editor::toggle_tracks_active ()
7249 TrackSelection& ts (selection->tracks);
7251 bool target = false;
7257 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7258 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7262 target = !rtv->_route->active();
7265 rtv->_route->set_active (target, this);
7271 Editor::remove_tracks ()
7273 /* this will delete GUI objects that may be the subject of an event
7274 handler in which this method is called. Defer actual deletion to the
7275 next idle callback, when all event handling is finished.
7277 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7281 Editor::idle_remove_tracks ()
7283 Session::StateProtector sp (_session);
7285 return false; /* do not call again */
7289 Editor::_remove_tracks ()
7291 TrackSelection& ts (selection->tracks);
7297 vector<string> choices;
7301 const char* trackstr;
7303 vector<boost::shared_ptr<Route> > routes;
7304 bool special_bus = false;
7306 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7307 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7311 if (rtv->is_track()) {
7316 routes.push_back (rtv->_route);
7318 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7323 if (special_bus && !Config->get_allow_special_bus_removal()) {
7324 MessageDialog msg (_("That would be bad news ...."),
7328 msg.set_secondary_text (string_compose (_(
7329 "Removing the master or monitor bus is such a bad idea\n\
7330 that %1 is not going to allow it.\n\
7332 If you really want to do this sort of thing\n\
7333 edit your ardour.rc file to set the\n\
7334 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7341 if (ntracks + nbusses == 0) {
7345 trackstr = P_("track", "tracks", ntracks);
7346 busstr = P_("bus", "busses", nbusses);
7350 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7351 "(You may also lose the playlists associated with the %2)\n\n"
7352 "This action cannot be undone, and the session file will be overwritten!"),
7353 ntracks, trackstr, nbusses, busstr);
7355 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7356 "(You may also lose the playlists associated with the %2)\n\n"
7357 "This action cannot be undone, and the session file will be overwritten!"),
7360 } else if (nbusses) {
7361 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7362 "This action cannot be undone, and the session file will be overwritten"),
7366 choices.push_back (_("No, do nothing."));
7367 if (ntracks + nbusses > 1) {
7368 choices.push_back (_("Yes, remove them."));
7370 choices.push_back (_("Yes, remove it."));
7375 title = string_compose (_("Remove %1"), trackstr);
7377 title = string_compose (_("Remove %1"), busstr);
7380 Choice prompter (title, prompt, choices);
7382 if (prompter.run () != 1) {
7387 Mixer_UI::instance()->selection().block_routes_changed (true);
7388 selection->block_tracks_changed (true);
7390 DisplaySuspender ds;
7391 boost::shared_ptr<RouteList> rl (new RouteList);
7392 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7395 _session->remove_routes (rl);
7397 /* TrackSelection and RouteList leave scope,
7398 * destructors are called,
7399 * diskstream drops references, save_state is called (again for every track)
7401 selection->block_tracks_changed (false);
7402 Mixer_UI::instance()->selection().block_routes_changed (false);
7403 selection->TracksChanged (); /* EMIT SIGNAL */
7407 Editor::do_insert_time ()
7409 if (selection->tracks.empty()) {
7413 InsertRemoveTimeDialog d (*this);
7414 int response = d.run ();
7416 if (response != RESPONSE_OK) {
7420 if (d.distance() == 0) {
7427 d.intersected_region_action (),
7431 d.move_glued_markers(),
7432 d.move_locked_markers(),
7438 Editor::insert_time (
7439 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7440 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7444 if (Config->get_edit_mode() == Lock) {
7447 bool in_command = false;
7449 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7451 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7455 /* don't operate on any playlist more than once, which could
7456 * happen if "all playlists" is enabled, but there is more
7457 * than 1 track using playlists "from" a given track.
7460 set<boost::shared_ptr<Playlist> > pl;
7462 if (all_playlists) {
7463 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7464 if (rtav && rtav->track ()) {
7465 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7466 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7471 if ((*x)->playlist ()) {
7472 pl.insert ((*x)->playlist ());
7476 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7478 (*i)->clear_changes ();
7479 (*i)->clear_owned_changes ();
7481 if (opt == SplitIntersected) {
7482 /* non musical split */
7483 (*i)->split (pos, 0);
7486 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7489 begin_reversible_command (_("insert time"));
7492 vector<Command*> cmds;
7494 _session->add_commands (cmds);
7496 _session->add_command (new StatefulDiffCommand (*i));
7500 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7503 begin_reversible_command (_("insert time"));
7506 rtav->route ()->shift (pos, frames);
7513 XMLNode& before (_session->locations()->get_state());
7514 Locations::LocationList copy (_session->locations()->list());
7516 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7518 Locations::LocationList::const_iterator tmp;
7520 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7521 bool const was_locked = (*i)->locked ();
7522 if (locked_markers_too) {
7526 if ((*i)->start() >= pos) {
7527 // move end first, in case we're moving by more than the length of the range
7528 if (!(*i)->is_mark()) {
7529 (*i)->set_end ((*i)->end() + frames);
7531 (*i)->set_start ((*i)->start() + frames);
7543 begin_reversible_command (_("insert time"));
7546 XMLNode& after (_session->locations()->get_state());
7547 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7553 begin_reversible_command (_("insert time"));
7556 XMLNode& before (_session->tempo_map().get_state());
7557 _session->tempo_map().insert_time (pos, frames);
7558 XMLNode& after (_session->tempo_map().get_state());
7559 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7563 commit_reversible_command ();
7568 Editor::do_remove_time ()
7570 if (selection->tracks.empty()) {
7574 InsertRemoveTimeDialog d (*this, true);
7576 int response = d.run ();
7578 if (response != RESPONSE_OK) {
7582 framecnt_t distance = d.distance();
7584 if (distance == 0) {
7594 d.move_glued_markers(),
7595 d.move_locked_markers(),
7601 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7602 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7604 if (Config->get_edit_mode() == Lock) {
7605 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7608 bool in_command = false;
7610 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7612 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7616 XMLNode &before = pl->get_state();
7618 std::list<AudioRange> rl;
7619 AudioRange ar(pos, pos+frames, 0);
7622 pl->shift (pos, -frames, true, ignore_music_glue);
7625 begin_reversible_command (_("remove time"));
7628 XMLNode &after = pl->get_state();
7630 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7634 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7637 begin_reversible_command (_("remove time"));
7640 rtav->route ()->shift (pos, -frames);
7644 std::list<Location*> loc_kill_list;
7649 XMLNode& before (_session->locations()->get_state());
7650 Locations::LocationList copy (_session->locations()->list());
7652 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7653 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7655 bool const was_locked = (*i)->locked ();
7656 if (locked_markers_too) {
7660 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7661 if ((*i)->end() >= pos
7662 && (*i)->end() < pos+frames
7663 && (*i)->start() >= pos
7664 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7666 loc_kill_list.push_back(*i);
7667 } else { // only start or end is included, try to do the right thing
7668 // move start before moving end, to avoid trying to move the end to before the start
7669 // if we're removing more time than the length of the range
7670 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7671 // start is within cut
7672 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7674 } else if ((*i)->start() >= pos+frames) {
7675 // start (and thus entire range) lies beyond end of cut
7676 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7679 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7680 // end is inside cut
7681 (*i)->set_end (pos); // bring the end to the cut
7683 } else if ((*i)->end() >= pos+frames) {
7684 // end is beyond end of cut
7685 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7690 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7691 loc_kill_list.push_back(*i);
7693 } else if ((*i)->start() >= pos) {
7694 (*i)->set_start ((*i)->start() -frames);
7704 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7705 _session->locations()->remove( *i );
7710 begin_reversible_command (_("remove time"));
7713 XMLNode& after (_session->locations()->get_state());
7714 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7719 XMLNode& before (_session->tempo_map().get_state());
7721 if (_session->tempo_map().remove_time (pos, frames) ) {
7723 begin_reversible_command (_("remove time"));
7726 XMLNode& after (_session->tempo_map().get_state());
7727 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7732 commit_reversible_command ();
7737 Editor::fit_selection ()
7739 if (!selection->tracks.empty()) {
7740 fit_tracks (selection->tracks);
7744 /* no selected tracks - use tracks with selected regions */
7746 if (!selection->regions.empty()) {
7747 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7748 tvl.push_back (&(*r)->get_time_axis_view ());
7754 } else if (internal_editing()) {
7755 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7758 if (entered_track) {
7759 tvl.push_back (entered_track);
7768 Editor::fit_tracks (TrackViewList & tracks)
7770 if (tracks.empty()) {
7774 uint32_t child_heights = 0;
7775 int visible_tracks = 0;
7777 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7779 if (!(*t)->marked_for_display()) {
7783 child_heights += (*t)->effective_height() - (*t)->current_height();
7787 /* compute the per-track height from:
7789 total canvas visible height -
7790 height that will be taken by visible children of selected
7791 tracks - height of the ruler/hscroll area
7793 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7794 double first_y_pos = DBL_MAX;
7796 if (h < TimeAxisView::preset_height (HeightSmall)) {
7797 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7798 /* too small to be displayed */
7802 undo_visual_stack.push_back (current_visual_state (true));
7803 PBD::Unwinder<bool> nsv (no_save_visual, true);
7805 /* build a list of all tracks, including children */
7808 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7810 TimeAxisView::Children c = (*i)->get_child_list ();
7811 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7812 all.push_back (j->get());
7817 // find selection range.
7818 // if someone knows how to user TrackViewList::iterator for this
7820 int selected_top = -1;
7821 int selected_bottom = -1;
7823 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7824 if ((*t)->marked_for_display ()) {
7825 if (tracks.contains(*t)) {
7826 if (selected_top == -1) {
7829 selected_bottom = i;
7835 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7836 if ((*t)->marked_for_display ()) {
7837 if (tracks.contains(*t)) {
7838 (*t)->set_height (h);
7839 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7841 if (i > selected_top && i < selected_bottom) {
7842 hide_track_in_display (*t);
7849 set the controls_layout height now, because waiting for its size
7850 request signal handler will cause the vertical adjustment setting to fail
7853 controls_layout.property_height () = _full_canvas_height;
7854 vertical_adjustment.set_value (first_y_pos);
7856 redo_visual_stack.push_back (current_visual_state (true));
7858 visible_tracks_selector.set_text (_("Sel"));
7862 Editor::save_visual_state (uint32_t n)
7864 while (visual_states.size() <= n) {
7865 visual_states.push_back (0);
7868 if (visual_states[n] != 0) {
7869 delete visual_states[n];
7872 visual_states[n] = current_visual_state (true);
7877 Editor::goto_visual_state (uint32_t n)
7879 if (visual_states.size() <= n) {
7883 if (visual_states[n] == 0) {
7887 use_visual_state (*visual_states[n]);
7891 Editor::start_visual_state_op (uint32_t n)
7893 save_visual_state (n);
7895 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7897 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7898 pup->set_text (buf);
7903 Editor::cancel_visual_state_op (uint32_t n)
7905 goto_visual_state (n);
7909 Editor::toggle_region_mute ()
7911 if (_ignore_region_action) {
7915 RegionSelection rs = get_regions_from_selection_and_entered ();
7921 if (rs.size() > 1) {
7922 begin_reversible_command (_("mute regions"));
7924 begin_reversible_command (_("mute region"));
7927 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7929 (*i)->region()->playlist()->clear_changes ();
7930 (*i)->region()->set_muted (!(*i)->region()->muted ());
7931 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7935 commit_reversible_command ();
7939 Editor::combine_regions ()
7941 /* foreach track with selected regions, take all selected regions
7942 and join them into a new region containing the subregions (as a
7946 typedef set<RouteTimeAxisView*> RTVS;
7949 if (selection->regions.empty()) {
7953 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7954 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7957 tracks.insert (rtv);
7961 begin_reversible_command (_("combine regions"));
7963 vector<RegionView*> new_selection;
7965 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7968 if ((rv = (*i)->combine_regions ()) != 0) {
7969 new_selection.push_back (rv);
7973 selection->clear_regions ();
7974 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7975 selection->add (*i);
7978 commit_reversible_command ();
7982 Editor::uncombine_regions ()
7984 typedef set<RouteTimeAxisView*> RTVS;
7987 if (selection->regions.empty()) {
7991 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7992 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7995 tracks.insert (rtv);
7999 begin_reversible_command (_("uncombine regions"));
8001 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8002 (*i)->uncombine_regions ();
8005 commit_reversible_command ();
8009 Editor::toggle_midi_input_active (bool flip_others)
8012 boost::shared_ptr<RouteList> rl (new RouteList);
8014 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8015 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8021 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8024 rl->push_back (rtav->route());
8025 onoff = !mt->input_active();
8029 _session->set_exclusive_input_active (rl, onoff, flip_others);
8032 static bool ok_fine (GdkEventAny*) { return true; }
8038 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8040 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8041 lock_dialog->get_vbox()->pack_start (*padlock);
8042 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8044 ArdourButton* b = manage (new ArdourButton);
8045 b->set_name ("lock button");
8046 b->set_text (_("Click to unlock"));
8047 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8048 lock_dialog->get_vbox()->pack_start (*b);
8050 lock_dialog->get_vbox()->show_all ();
8051 lock_dialog->set_size_request (200, 200);
8054 delete _main_menu_disabler;
8055 _main_menu_disabler = new MainMenuDisabler;
8057 lock_dialog->present ();
8059 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8065 lock_dialog->hide ();
8067 delete _main_menu_disabler;
8068 _main_menu_disabler = 0;
8070 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8071 start_lock_event_timing ();
8076 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8078 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8082 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8084 Timers::TimerSuspender t;
8085 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8086 Gtkmm2ext::UI::instance()->flush_pending (1);
8090 Editor::bring_all_sources_into_session ()
8097 ArdourDialog w (_("Moving embedded files into session folder"));
8098 w.get_vbox()->pack_start (msg);
8101 /* flush all pending GUI events because we're about to start copying
8105 Timers::TimerSuspender t;
8106 Gtkmm2ext::UI::instance()->flush_pending (3);
8110 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));