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,
174 RegionSelection pre_selected_regions = selection->regions;
175 bool working_on_selection = !pre_selected_regions.empty();
177 list<boost::shared_ptr<Playlist> > used_playlists;
178 list<RouteTimeAxisView*> used_trackviews;
180 if (regions.empty()) {
184 begin_reversible_command (_("split"));
186 // if splitting a single region, and snap-to is using
187 // region boundaries, don't pay attention to them
189 if (regions.size() == 1) {
190 switch (_snap_type) {
191 case SnapToRegionStart:
192 case SnapToRegionSync:
193 case SnapToRegionEnd:
206 EditorFreeze(); /* Emit Signal */
209 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
211 RegionSelection::iterator tmp;
213 /* XXX this test needs to be more complicated, to make sure we really
214 have something to split.
217 if (!(*a)->region()->covers (where)) {
225 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
233 /* we haven't seen this playlist before */
235 /* remember used playlists so we can thaw them later */
236 used_playlists.push_back(pl);
238 TimeAxisView& tv = (*a)->get_time_axis_view();
239 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
241 used_trackviews.push_back (rtv);
248 pl->clear_changes ();
249 pl->split_region ((*a)->region(), where, sub_num);
250 _session->add_command (new StatefulDiffCommand (pl));
256 latest_regionviews.clear ();
258 vector<sigc::connection> region_added_connections;
260 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
261 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
264 while (used_playlists.size() > 0) {
265 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
267 used_playlists.pop_front();
270 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
275 EditorThaw(); /* Emit Signal */
278 if (working_on_selection) {
279 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
281 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
282 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
283 /* There are three classes of regions that we might want selected after
284 splitting selected regions:
285 - regions selected before the split operation, and unaffected by it
286 - newly-created regions before the split
287 - newly-created regions after the split
290 if (rsas & Existing) {
291 // region selections that existed before the split.
292 selection->add ( pre_selected_regions );
295 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
296 if ((*ri)->region()->position() < where) {
297 // new regions created before the split
298 if (rsas & NewlyCreatedLeft) {
299 selection->add (*ri);
302 // new regions created after the split
303 if (rsas & NewlyCreatedRight) {
304 selection->add (*ri);
308 _ignore_follow_edits = false;
310 _ignore_follow_edits = true;
311 if( working_on_selection ) {
312 selection->add (latest_regionviews); //these are the new regions created after the split
314 _ignore_follow_edits = false;
317 commit_reversible_command ();
320 /** Move one extreme of the current range selection. If more than one range is selected,
321 * the start of the earliest range or the end of the latest range is moved.
323 * @param move_end true to move the end of the current range selection, false to move
325 * @param next true to move the extreme to the next region boundary, false to move to
329 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
331 if (selection->time.start() == selection->time.end_frame()) {
335 framepos_t start = selection->time.start ();
336 framepos_t end = selection->time.end_frame ();
338 /* the position of the thing we may move */
339 framepos_t pos = move_end ? end : start;
340 int dir = next ? 1 : -1;
342 /* so we don't find the current region again */
343 if (dir > 0 || pos > 0) {
347 framepos_t const target = get_region_boundary (pos, dir, true, false);
362 begin_reversible_selection_op (_("alter selection"));
363 selection->set_preserving_all_ranges (start, end);
364 commit_reversible_selection_op ();
368 Editor::nudge_forward_release (GdkEventButton* ev)
370 if (ev->state & Keyboard::PrimaryModifier) {
371 nudge_forward (false, true);
373 nudge_forward (false, false);
379 Editor::nudge_backward_release (GdkEventButton* ev)
381 if (ev->state & Keyboard::PrimaryModifier) {
382 nudge_backward (false, true);
384 nudge_backward (false, false);
391 Editor::nudge_forward (bool next, bool force_playhead)
394 framepos_t next_distance;
400 RegionSelection rs = get_regions_from_selection_and_entered ();
402 if (!force_playhead && !rs.empty()) {
404 begin_reversible_command (_("nudge regions forward"));
406 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
407 boost::shared_ptr<Region> r ((*i)->region());
409 distance = get_nudge_distance (r->position(), next_distance);
412 distance = next_distance;
416 r->set_position (r->position() + distance);
417 _session->add_command (new StatefulDiffCommand (r));
420 commit_reversible_command ();
423 } else if (!force_playhead && !selection->markers.empty()) {
426 bool in_command = false;
428 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
430 Location* loc = find_location_from_marker ((*i), is_start);
434 XMLNode& before (loc->get_state());
437 distance = get_nudge_distance (loc->start(), next_distance);
439 distance = next_distance;
441 if (max_framepos - distance > loc->start() + loc->length()) {
442 loc->set_start (loc->start() + distance);
444 loc->set_start (max_framepos - loc->length());
447 distance = get_nudge_distance (loc->end(), next_distance);
449 distance = next_distance;
451 if (max_framepos - distance > loc->end()) {
452 loc->set_end (loc->end() + distance);
454 loc->set_end (max_framepos);
456 if (loc->is_session_range()) {
457 _session->set_end_is_free (false);
461 begin_reversible_command (_("nudge location forward"));
464 XMLNode& after (loc->get_state());
465 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
470 commit_reversible_command ();
473 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
474 _session->request_locate (playhead_cursor->current_frame () + distance);
479 Editor::nudge_backward (bool next, bool force_playhead)
482 framepos_t next_distance;
488 RegionSelection rs = get_regions_from_selection_and_entered ();
490 if (!force_playhead && !rs.empty()) {
492 begin_reversible_command (_("nudge regions backward"));
494 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
495 boost::shared_ptr<Region> r ((*i)->region());
497 distance = get_nudge_distance (r->position(), next_distance);
500 distance = next_distance;
505 if (r->position() > distance) {
506 r->set_position (r->position() - distance);
510 _session->add_command (new StatefulDiffCommand (r));
513 commit_reversible_command ();
515 } else if (!force_playhead && !selection->markers.empty()) {
518 bool in_command = false;
520 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
522 Location* loc = find_location_from_marker ((*i), is_start);
526 XMLNode& before (loc->get_state());
529 distance = get_nudge_distance (loc->start(), next_distance);
531 distance = next_distance;
533 if (distance < loc->start()) {
534 loc->set_start (loc->start() - distance);
539 distance = get_nudge_distance (loc->end(), next_distance);
542 distance = next_distance;
545 if (distance < loc->end() - loc->length()) {
546 loc->set_end (loc->end() - distance);
548 loc->set_end (loc->length());
550 if (loc->is_session_range()) {
551 _session->set_end_is_free (false);
555 begin_reversible_command (_("nudge location forward"));
558 XMLNode& after (loc->get_state());
559 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
563 commit_reversible_command ();
568 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
570 if (playhead_cursor->current_frame () > distance) {
571 _session->request_locate (playhead_cursor->current_frame () - distance);
573 _session->goto_start();
579 Editor::nudge_forward_capture_offset ()
581 RegionSelection rs = get_regions_from_selection_and_entered ();
583 if (!_session || rs.empty()) {
587 begin_reversible_command (_("nudge forward"));
589 framepos_t const distance = _session->worst_output_latency();
591 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
592 boost::shared_ptr<Region> r ((*i)->region());
595 r->set_position (r->position() + distance);
596 _session->add_command(new StatefulDiffCommand (r));
599 commit_reversible_command ();
603 Editor::nudge_backward_capture_offset ()
605 RegionSelection rs = get_regions_from_selection_and_entered ();
607 if (!_session || rs.empty()) {
611 begin_reversible_command (_("nudge backward"));
613 framepos_t const distance = _session->worst_output_latency();
615 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
616 boost::shared_ptr<Region> r ((*i)->region());
620 if (r->position() > distance) {
621 r->set_position (r->position() - distance);
625 _session->add_command(new StatefulDiffCommand (r));
628 commit_reversible_command ();
631 struct RegionSelectionPositionSorter {
632 bool operator() (RegionView* a, RegionView* b) {
633 return a->region()->position() < b->region()->position();
638 Editor::sequence_regions ()
641 framepos_t r_end_prev;
649 RegionSelection rs = get_regions_from_selection_and_entered ();
650 rs.sort(RegionSelectionPositionSorter());
654 bool in_command = false;
656 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
657 boost::shared_ptr<Region> r ((*i)->region());
665 if(r->position_locked())
672 r->set_position(r_end_prev);
676 begin_reversible_command (_("sequence regions"));
679 _session->add_command (new StatefulDiffCommand (r));
681 r_end=r->position() + r->length();
687 commit_reversible_command ();
696 Editor::move_to_start ()
698 _session->goto_start ();
702 Editor::move_to_end ()
705 _session->request_locate (_session->current_end_frame());
709 Editor::build_region_boundary_cache ()
712 vector<RegionPoint> interesting_points;
713 boost::shared_ptr<Region> r;
714 TrackViewList tracks;
717 region_boundary_cache.clear ();
723 switch (_snap_type) {
724 case SnapToRegionStart:
725 interesting_points.push_back (Start);
727 case SnapToRegionEnd:
728 interesting_points.push_back (End);
730 case SnapToRegionSync:
731 interesting_points.push_back (SyncPoint);
733 case SnapToRegionBoundary:
734 interesting_points.push_back (Start);
735 interesting_points.push_back (End);
738 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
739 abort(); /*NOTREACHED*/
743 TimeAxisView *ontrack = 0;
746 if (!selection->tracks.empty()) {
747 tlist = selection->tracks.filter_to_unique_playlists ();
749 tlist = track_views.filter_to_unique_playlists ();
752 while (pos < _session->current_end_frame() && !at_end) {
755 framepos_t lpos = max_framepos;
757 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
759 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
760 if (*p == interesting_points.back()) {
763 /* move to next point type */
769 rpos = r->first_frame();
773 rpos = r->last_frame();
777 rpos = r->sync_position ();
785 RouteTimeAxisView *rtav;
787 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
788 if (rtav->track() != 0) {
789 speed = rtav->track()->speed();
793 rpos = track_frame_to_session_frame (rpos, speed);
799 /* prevent duplicates, but we don't use set<> because we want to be able
803 vector<framepos_t>::iterator ri;
805 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
811 if (ri == region_boundary_cache.end()) {
812 region_boundary_cache.push_back (rpos);
819 /* finally sort to be sure that the order is correct */
821 sort (region_boundary_cache.begin(), region_boundary_cache.end());
824 boost::shared_ptr<Region>
825 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
827 TrackViewList::iterator i;
828 framepos_t closest = max_framepos;
829 boost::shared_ptr<Region> ret;
833 framepos_t track_frame;
834 RouteTimeAxisView *rtav;
836 for (i = tracks.begin(); i != tracks.end(); ++i) {
839 boost::shared_ptr<Region> r;
842 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
843 if (rtav->track()!=0)
844 track_speed = rtav->track()->speed();
847 track_frame = session_frame_to_track_frame(frame, track_speed);
849 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
855 rpos = r->first_frame ();
859 rpos = r->last_frame ();
863 rpos = r->sync_position ();
867 // rpos is a "track frame", converting it to "_session frame"
868 rpos = track_frame_to_session_frame(rpos, track_speed);
871 distance = rpos - frame;
873 distance = frame - rpos;
876 if (distance < closest) {
888 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
890 framecnt_t distance = max_framepos;
891 framepos_t current_nearest = -1;
893 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
894 framepos_t contender;
897 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
903 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
907 d = ::llabs (pos - contender);
910 current_nearest = contender;
915 return current_nearest;
919 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
924 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
926 if (!selection->tracks.empty()) {
928 target = find_next_region_boundary (pos, dir, selection->tracks);
932 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
933 get_onscreen_tracks (tvl);
934 target = find_next_region_boundary (pos, dir, tvl);
936 target = find_next_region_boundary (pos, dir, track_views);
942 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
943 get_onscreen_tracks (tvl);
944 target = find_next_region_boundary (pos, dir, tvl);
946 target = find_next_region_boundary (pos, dir, track_views);
954 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
956 framepos_t pos = playhead_cursor->current_frame ();
963 // so we don't find the current region again..
964 if (dir > 0 || pos > 0) {
968 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
972 _session->request_locate (target);
976 Editor::cursor_to_next_region_boundary (bool with_selection)
978 cursor_to_region_boundary (with_selection, 1);
982 Editor::cursor_to_previous_region_boundary (bool with_selection)
984 cursor_to_region_boundary (with_selection, -1);
988 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
990 boost::shared_ptr<Region> r;
991 framepos_t pos = cursor->current_frame ();
997 TimeAxisView *ontrack = 0;
999 // so we don't find the current region again..
1003 if (!selection->tracks.empty()) {
1005 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1007 } else if (clicked_axisview) {
1010 t.push_back (clicked_axisview);
1012 r = find_next_region (pos, point, dir, t, &ontrack);
1016 r = find_next_region (pos, point, dir, track_views, &ontrack);
1025 pos = r->first_frame ();
1029 pos = r->last_frame ();
1033 pos = r->sync_position ();
1038 RouteTimeAxisView *rtav;
1040 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1041 if (rtav->track() != 0) {
1042 speed = rtav->track()->speed();
1046 pos = track_frame_to_session_frame(pos, speed);
1048 if (cursor == playhead_cursor) {
1049 _session->request_locate (pos);
1051 cursor->set_position (pos);
1056 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1058 cursor_to_region_point (cursor, point, 1);
1062 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1064 cursor_to_region_point (cursor, point, -1);
1068 Editor::cursor_to_selection_start (EditorCursor *cursor)
1072 switch (mouse_mode) {
1074 if (!selection->regions.empty()) {
1075 pos = selection->regions.start();
1080 if (!selection->time.empty()) {
1081 pos = selection->time.start ();
1089 if (cursor == playhead_cursor) {
1090 _session->request_locate (pos);
1092 cursor->set_position (pos);
1097 Editor::cursor_to_selection_end (EditorCursor *cursor)
1101 switch (mouse_mode) {
1103 if (!selection->regions.empty()) {
1104 pos = selection->regions.end_frame();
1109 if (!selection->time.empty()) {
1110 pos = selection->time.end_frame ();
1118 if (cursor == playhead_cursor) {
1119 _session->request_locate (pos);
1121 cursor->set_position (pos);
1126 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1136 if (selection->markers.empty()) {
1140 if (!mouse_frame (mouse, ignored)) {
1144 add_location_mark (mouse);
1147 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1151 framepos_t pos = loc->start();
1153 // so we don't find the current region again..
1154 if (dir > 0 || pos > 0) {
1158 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1162 loc->move_to (target);
1166 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1168 selected_marker_to_region_boundary (with_selection, 1);
1172 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1174 selected_marker_to_region_boundary (with_selection, -1);
1178 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1180 boost::shared_ptr<Region> r;
1185 if (!_session || selection->markers.empty()) {
1189 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1193 TimeAxisView *ontrack = 0;
1197 // so we don't find the current region again..
1201 if (!selection->tracks.empty()) {
1203 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1207 r = find_next_region (pos, point, dir, track_views, &ontrack);
1216 pos = r->first_frame ();
1220 pos = r->last_frame ();
1224 pos = r->adjust_to_sync (r->first_frame());
1229 RouteTimeAxisView *rtav;
1231 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1232 if (rtav->track() != 0) {
1233 speed = rtav->track()->speed();
1237 pos = track_frame_to_session_frame(pos, speed);
1243 Editor::selected_marker_to_next_region_point (RegionPoint point)
1245 selected_marker_to_region_point (point, 1);
1249 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1251 selected_marker_to_region_point (point, -1);
1255 Editor::selected_marker_to_selection_start ()
1261 if (!_session || selection->markers.empty()) {
1265 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1269 switch (mouse_mode) {
1271 if (!selection->regions.empty()) {
1272 pos = selection->regions.start();
1277 if (!selection->time.empty()) {
1278 pos = selection->time.start ();
1290 Editor::selected_marker_to_selection_end ()
1296 if (!_session || selection->markers.empty()) {
1300 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1304 switch (mouse_mode) {
1306 if (!selection->regions.empty()) {
1307 pos = selection->regions.end_frame();
1312 if (!selection->time.empty()) {
1313 pos = selection->time.end_frame ();
1325 Editor::scroll_playhead (bool forward)
1327 framepos_t pos = playhead_cursor->current_frame ();
1328 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1331 if (pos == max_framepos) {
1335 if (pos < max_framepos - delta) {
1354 _session->request_locate (pos);
1358 Editor::cursor_align (bool playhead_to_edit)
1364 if (playhead_to_edit) {
1366 if (selection->markers.empty()) {
1370 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1373 /* move selected markers to playhead */
1375 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1378 Location* loc = find_location_from_marker (*i, ignored);
1380 if (loc->is_mark()) {
1381 loc->set_start (playhead_cursor->current_frame ());
1383 loc->set (playhead_cursor->current_frame (),
1384 playhead_cursor->current_frame () + loc->length());
1391 Editor::scroll_backward (float pages)
1393 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1394 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1397 if (leftmost_frame < cnt) {
1400 frame = leftmost_frame - cnt;
1403 reset_x_origin (frame);
1407 Editor::scroll_forward (float pages)
1409 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1410 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1413 if (max_framepos - cnt < leftmost_frame) {
1414 frame = max_framepos - cnt;
1416 frame = leftmost_frame + cnt;
1419 reset_x_origin (frame);
1423 Editor::scroll_tracks_down ()
1425 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1426 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1427 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1430 vertical_adjustment.set_value (vert_value);
1434 Editor::scroll_tracks_up ()
1436 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1440 Editor::scroll_tracks_down_line ()
1442 double vert_value = vertical_adjustment.get_value() + 60;
1444 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1445 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1448 vertical_adjustment.set_value (vert_value);
1452 Editor::scroll_tracks_up_line ()
1454 reset_y_origin (vertical_adjustment.get_value() - 60);
1458 Editor::scroll_down_one_track (bool skip_child_views)
1460 TrackViewList::reverse_iterator next = track_views.rend();
1461 const double top_of_trackviews = vertical_adjustment.get_value();
1463 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1464 if ((*t)->hidden()) {
1468 /* If this is the upper-most visible trackview, we want to display
1469 * the one above it (next)
1471 * Note that covers_y_position() is recursive and includes child views
1473 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1476 if (skip_child_views) {
1479 /* automation lane (one level, non-recursive)
1481 * - if no automation lane exists -> move to next tack
1482 * - if the first (here: bottom-most) matches -> move to next tack
1483 * - if no y-axis match is found -> the current track is at the top
1484 * -> move to last (here: top-most) automation lane
1486 TimeAxisView::Children kids = (*t)->get_child_list();
1487 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1489 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1490 if ((*ci)->hidden()) {
1494 std::pair<TimeAxisView*,double> dev;
1495 dev = (*ci)->covers_y_position (top_of_trackviews);
1497 /* some automation lane is currently at the top */
1498 if (ci == kids.rbegin()) {
1499 /* first (bottom-most) autmation lane is at the top.
1500 * -> move to next track
1509 if (nkid != kids.rend()) {
1510 ensure_time_axis_view_is_visible (**nkid, true);
1518 /* move to the track below the first one that covers the */
1520 if (next != track_views.rend()) {
1521 ensure_time_axis_view_is_visible (**next, true);
1529 Editor::scroll_up_one_track (bool skip_child_views)
1531 TrackViewList::iterator prev = track_views.end();
1532 double top_of_trackviews = vertical_adjustment.get_value ();
1534 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1536 if ((*t)->hidden()) {
1540 /* find the trackview at the top of the trackview group
1542 * Note that covers_y_position() is recursive and includes child views
1544 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1547 if (skip_child_views) {
1550 /* automation lane (one level, non-recursive)
1552 * - if no automation lane exists -> move to prev tack
1553 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1554 * (actually last automation lane of previous track, see below)
1555 * - if first (top-most) lane is at the top -> move to this track
1556 * - else move up one lane
1558 TimeAxisView::Children kids = (*t)->get_child_list();
1559 TimeAxisView::Children::iterator pkid = kids.end();
1561 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1562 if ((*ci)->hidden()) {
1566 std::pair<TimeAxisView*,double> dev;
1567 dev = (*ci)->covers_y_position (top_of_trackviews);
1569 /* some automation lane is currently at the top */
1570 if (ci == kids.begin()) {
1571 /* first (top-most) autmation lane is at the top.
1572 * jump directly to this track's top
1574 ensure_time_axis_view_is_visible (**t, true);
1577 else if (pkid != kids.end()) {
1578 /* some other automation lane is at the top.
1579 * move up to prev automation lane.
1581 ensure_time_axis_view_is_visible (**pkid, true);
1584 assert(0); // not reached
1595 if (prev != track_views.end()) {
1596 // move to bottom-most automation-lane of the previous track
1597 TimeAxisView::Children kids = (*prev)->get_child_list();
1598 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1599 if (!skip_child_views) {
1600 // find the last visible lane
1601 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1602 if (!(*ci)->hidden()) {
1608 if (pkid != kids.rend()) {
1609 ensure_time_axis_view_is_visible (**pkid, true);
1611 ensure_time_axis_view_is_visible (**prev, true);
1620 Editor::scroll_left_step ()
1622 framepos_t xdelta = (current_page_samples() / 8);
1624 if (leftmost_frame > xdelta) {
1625 reset_x_origin (leftmost_frame - xdelta);
1633 Editor::scroll_right_step ()
1635 framepos_t xdelta = (current_page_samples() / 8);
1637 if (max_framepos - xdelta > leftmost_frame) {
1638 reset_x_origin (leftmost_frame + xdelta);
1640 reset_x_origin (max_framepos - current_page_samples());
1645 Editor::scroll_left_half_page ()
1647 framepos_t xdelta = (current_page_samples() / 2);
1648 if (leftmost_frame > xdelta) {
1649 reset_x_origin (leftmost_frame - xdelta);
1656 Editor::scroll_right_half_page ()
1658 framepos_t xdelta = (current_page_samples() / 2);
1659 if (max_framepos - xdelta > leftmost_frame) {
1660 reset_x_origin (leftmost_frame + xdelta);
1662 reset_x_origin (max_framepos - current_page_samples());
1669 Editor::tav_zoom_step (bool coarser)
1671 DisplaySuspender ds;
1675 if (selection->tracks.empty()) {
1678 ts = &selection->tracks;
1681 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1682 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1683 tv->step_height (coarser);
1688 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1690 DisplaySuspender ds;
1694 if (selection->tracks.empty() || force_all) {
1697 ts = &selection->tracks;
1700 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1701 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1702 uint32_t h = tv->current_height ();
1707 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1712 tv->set_height (h + 5);
1718 Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1720 Editing::ZoomFocus temp_focus = zoom_focus;
1721 zoom_focus = Editing::ZoomFocusMouse;
1722 temporal_zoom_step_scale (zoom_out, scale);
1723 zoom_focus = temp_focus;
1727 Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1729 temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1733 Editor::temporal_zoom_step (bool zoom_out)
1735 temporal_zoom_step_scale (zoom_out, 2.0);
1739 Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1741 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1743 framecnt_t nspp = samples_per_pixel;
1747 if (nspp == samples_per_pixel) {
1752 if (nspp == samples_per_pixel) {
1757 temporal_zoom (nspp);
1761 Editor::temporal_zoom (framecnt_t fpp)
1767 framepos_t current_page = current_page_samples();
1768 framepos_t current_leftmost = leftmost_frame;
1769 framepos_t current_rightmost;
1770 framepos_t current_center;
1771 framepos_t new_page_size;
1772 framepos_t half_page_size;
1773 framepos_t leftmost_after_zoom = 0;
1775 bool in_track_canvas;
1776 bool use_mouse_frame = true;
1780 if (fpp == samples_per_pixel) {
1784 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1785 // segfaults for lack of memory. If somebody decides this is not high enough I
1786 // believe it can be raisen to higher values but some limit must be in place.
1788 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1789 // all of which is used for the editor track displays. The whole day
1790 // would be 4147200000 samples, so 2592000 samples per pixel.
1792 nfpp = min (fpp, (framecnt_t) 2592000);
1793 nfpp = max ((framecnt_t) 1, nfpp);
1795 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1796 half_page_size = new_page_size / 2;
1798 switch (zoom_focus) {
1800 leftmost_after_zoom = current_leftmost;
1803 case ZoomFocusRight:
1804 current_rightmost = leftmost_frame + current_page;
1805 if (current_rightmost < new_page_size) {
1806 leftmost_after_zoom = 0;
1808 leftmost_after_zoom = current_rightmost - new_page_size;
1812 case ZoomFocusCenter:
1813 current_center = current_leftmost + (current_page/2);
1814 if (current_center < half_page_size) {
1815 leftmost_after_zoom = 0;
1817 leftmost_after_zoom = current_center - half_page_size;
1821 case ZoomFocusPlayhead:
1822 /* centre playhead */
1823 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1826 leftmost_after_zoom = 0;
1827 } else if (l > max_framepos) {
1828 leftmost_after_zoom = max_framepos - new_page_size;
1830 leftmost_after_zoom = (framepos_t) l;
1834 case ZoomFocusMouse:
1835 /* try to keep the mouse over the same point in the display */
1837 if (_drags->active()) {
1838 where = _drags->current_pointer_frame ();
1839 } else if (!mouse_frame (where, in_track_canvas)) {
1840 use_mouse_frame = false;
1843 if (use_mouse_frame) {
1844 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1847 leftmost_after_zoom = 0;
1848 } else if (l > max_framepos) {
1849 leftmost_after_zoom = max_framepos - new_page_size;
1851 leftmost_after_zoom = (framepos_t) l;
1854 /* use playhead instead */
1855 where = playhead_cursor->current_frame ();
1857 if (where < half_page_size) {
1858 leftmost_after_zoom = 0;
1860 leftmost_after_zoom = where - half_page_size;
1866 /* try to keep the edit point in the same place */
1867 where = get_preferred_edit_position ();
1871 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1874 leftmost_after_zoom = 0;
1875 } else if (l > max_framepos) {
1876 leftmost_after_zoom = max_framepos - new_page_size;
1878 leftmost_after_zoom = (framepos_t) l;
1882 /* edit point not defined */
1889 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1891 reposition_and_zoom (leftmost_after_zoom, nfpp);
1895 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1897 /* this func helps make sure we leave a little space
1898 at each end of the editor so that the zoom doesn't fit the region
1899 precisely to the screen.
1902 GdkScreen* screen = gdk_screen_get_default ();
1903 const gint pixwidth = gdk_screen_get_width (screen);
1904 const gint mmwidth = gdk_screen_get_width_mm (screen);
1905 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1906 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1908 const framepos_t range = end - start;
1909 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1910 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1912 if (start > extra_samples) {
1913 start -= extra_samples;
1918 if (max_framepos - extra_samples > end) {
1919 end += extra_samples;
1926 Editor::temporal_zoom_region (bool both_axes)
1928 framepos_t start = max_framepos;
1930 set<TimeAxisView*> tracks;
1932 if ( !get_selection_extents(start, end) )
1935 calc_extra_zoom_edges (start, end);
1937 /* if we're zooming on both axes we need to save track heights etc.
1940 undo_visual_stack.push_back (current_visual_state (both_axes));
1942 PBD::Unwinder<bool> nsv (no_save_visual, true);
1944 temporal_zoom_by_frame (start, end);
1947 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1949 /* set visible track heights appropriately */
1951 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1952 (*t)->set_height (per_track_height);
1955 /* hide irrelevant tracks */
1957 DisplaySuspender ds;
1959 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1960 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1961 hide_track_in_display (*i);
1965 vertical_adjustment.set_value (0.0);
1968 redo_visual_stack.push_back (current_visual_state (both_axes));
1973 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1975 start = max_framepos;
1979 //ToDo: if notes are selected, set extents to that selection
1981 //ToDo: if control points are selected, set extents to that selection
1983 if ( !selection->regions.empty() ) {
1984 RegionSelection rs = get_regions_from_selection_and_entered ();
1986 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1988 if ((*i)->region()->position() < start) {
1989 start = (*i)->region()->position();
1992 if ((*i)->region()->last_frame() + 1 > end) {
1993 end = (*i)->region()->last_frame() + 1;
1997 } else if (!selection->time.empty()) {
1998 start = selection->time.start();
1999 end = selection->time.end_frame();
2001 ret = false; //no selection found
2004 if ((start == 0 && end == 0) || end < start) {
2013 Editor::temporal_zoom_selection (bool both_axes)
2015 if (!selection) return;
2017 //ToDo: if notes are selected, zoom to that
2019 //ToDo: if control points are selected, zoom to that
2021 //if region(s) are selected, zoom to that
2022 if ( !selection->regions.empty() )
2023 temporal_zoom_region (both_axes);
2025 //if a range is selected, zoom to that
2026 if (!selection->time.empty()) {
2028 framepos_t start, end;
2029 if (get_selection_extents (start, end)) {
2030 calc_extra_zoom_edges(start, end);
2031 temporal_zoom_by_frame (start, end);
2041 Editor::temporal_zoom_session ()
2043 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2046 framecnt_t start = _session->current_start_frame();
2047 framecnt_t end = _session->current_end_frame();
2049 if (_session->actively_recording () ) {
2050 framepos_t cur = playhead_cursor->current_frame ();
2052 /* recording beyond the end marker; zoom out
2053 * by 5 seconds more so that if 'follow
2054 * playhead' is active we don't immediately
2057 end = cur + _session->frame_rate() * 5;
2061 if ((start == 0 && end == 0) || end < start) {
2065 calc_extra_zoom_edges(start, end);
2067 temporal_zoom_by_frame (start, end);
2072 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2074 if (!_session) return;
2076 if ((start == 0 && end == 0) || end < start) {
2080 framepos_t range = end - start;
2082 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2084 framepos_t new_page = range;
2085 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2086 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2088 if (new_leftmost > middle) {
2092 if (new_leftmost < 0) {
2096 reposition_and_zoom (new_leftmost, new_fpp);
2100 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2106 framecnt_t range_before = frame - leftmost_frame;
2110 if (samples_per_pixel <= 1) {
2113 new_spp = samples_per_pixel + (samples_per_pixel/2);
2115 range_before += range_before/2;
2117 if (samples_per_pixel >= 1) {
2118 new_spp = samples_per_pixel - (samples_per_pixel/2);
2120 /* could bail out here since we cannot zoom any finer,
2121 but leave that to the equality test below
2123 new_spp = samples_per_pixel;
2126 range_before -= range_before/2;
2129 if (new_spp == samples_per_pixel) {
2133 /* zoom focus is automatically taken as @param frame when this
2137 framepos_t new_leftmost = frame - (framepos_t)range_before;
2139 if (new_leftmost > frame) {
2143 if (new_leftmost < 0) {
2147 reposition_and_zoom (new_leftmost, new_spp);
2152 Editor::choose_new_marker_name(string &name) {
2154 if (!UIConfiguration::instance().get_name_new_markers()) {
2155 /* don't prompt user for a new name */
2159 ArdourPrompter dialog (true);
2161 dialog.set_prompt (_("New Name:"));
2163 dialog.set_title (_("New Location Marker"));
2165 dialog.set_name ("MarkNameWindow");
2166 dialog.set_size_request (250, -1);
2167 dialog.set_position (Gtk::WIN_POS_MOUSE);
2169 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2170 dialog.set_initial_text (name);
2174 switch (dialog.run ()) {
2175 case RESPONSE_ACCEPT:
2181 dialog.get_result(name);
2188 Editor::add_location_from_selection ()
2192 if (selection->time.empty()) {
2196 if (_session == 0 || clicked_axisview == 0) {
2200 framepos_t start = selection->time[clicked_selection].start;
2201 framepos_t end = selection->time[clicked_selection].end;
2203 _session->locations()->next_available_name(rangename,"selection");
2204 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2206 begin_reversible_command (_("add marker"));
2208 XMLNode &before = _session->locations()->get_state();
2209 _session->locations()->add (location, true);
2210 XMLNode &after = _session->locations()->get_state();
2211 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2213 commit_reversible_command ();
2217 Editor::add_location_mark (framepos_t where)
2221 select_new_marker = true;
2223 _session->locations()->next_available_name(markername,"mark");
2224 if (!choose_new_marker_name(markername)) {
2227 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2228 begin_reversible_command (_("add marker"));
2230 XMLNode &before = _session->locations()->get_state();
2231 _session->locations()->add (location, true);
2232 XMLNode &after = _session->locations()->get_state();
2233 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2235 commit_reversible_command ();
2239 Editor::set_session_start_from_playhead ()
2245 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2246 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2248 XMLNode &before = loc->get_state();
2250 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2252 XMLNode &after = loc->get_state();
2254 begin_reversible_command (_("Set session start"));
2256 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2258 commit_reversible_command ();
2263 Editor::set_session_end_from_playhead ()
2269 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2270 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2272 XMLNode &before = loc->get_state();
2274 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2276 XMLNode &after = loc->get_state();
2278 begin_reversible_command (_("Set session start"));
2280 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2282 commit_reversible_command ();
2285 _session->set_end_is_free (false);
2290 Editor::toggle_location_at_playhead_cursor ()
2292 if (!do_remove_location_at_playhead_cursor())
2294 add_location_from_playhead_cursor();
2299 Editor::add_location_from_playhead_cursor ()
2301 add_location_mark (_session->audible_frame());
2305 Editor::do_remove_location_at_playhead_cursor ()
2307 bool removed = false;
2310 XMLNode &before = _session->locations()->get_state();
2312 //find location(s) at this time
2313 Locations::LocationList locs;
2314 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2315 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2316 if ((*i)->is_mark()) {
2317 _session->locations()->remove (*i);
2324 begin_reversible_command (_("remove marker"));
2325 XMLNode &after = _session->locations()->get_state();
2326 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2327 commit_reversible_command ();
2334 Editor::remove_location_at_playhead_cursor ()
2336 do_remove_location_at_playhead_cursor ();
2339 /** Add a range marker around each selected region */
2341 Editor::add_locations_from_region ()
2343 RegionSelection rs = get_regions_from_selection_and_entered ();
2348 bool commit = false;
2350 XMLNode &before = _session->locations()->get_state();
2352 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2354 boost::shared_ptr<Region> region = (*i)->region ();
2356 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2358 _session->locations()->add (location, true);
2363 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2364 XMLNode &after = _session->locations()->get_state();
2365 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2366 commit_reversible_command ();
2370 /** Add a single range marker around all selected regions */
2372 Editor::add_location_from_region ()
2374 RegionSelection rs = get_regions_from_selection_and_entered ();
2380 XMLNode &before = _session->locations()->get_state();
2384 if (rs.size() > 1) {
2385 _session->locations()->next_available_name(markername, "regions");
2387 RegionView* rv = *(rs.begin());
2388 boost::shared_ptr<Region> region = rv->region();
2389 markername = region->name();
2392 if (!choose_new_marker_name(markername)) {
2396 // single range spanning all selected
2397 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2398 _session->locations()->add (location, true);
2400 begin_reversible_command (_("add marker"));
2401 XMLNode &after = _session->locations()->get_state();
2402 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2403 commit_reversible_command ();
2409 Editor::jump_forward_to_mark ()
2415 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2421 _session->request_locate (pos, _session->transport_rolling());
2425 Editor::jump_backward_to_mark ()
2431 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2437 _session->request_locate (pos, _session->transport_rolling());
2443 framepos_t const pos = _session->audible_frame ();
2446 _session->locations()->next_available_name (markername, "mark");
2448 if (!choose_new_marker_name (markername)) {
2452 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2456 Editor::clear_markers ()
2459 begin_reversible_command (_("clear markers"));
2461 XMLNode &before = _session->locations()->get_state();
2462 _session->locations()->clear_markers ();
2463 XMLNode &after = _session->locations()->get_state();
2464 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2466 commit_reversible_command ();
2471 Editor::clear_ranges ()
2474 begin_reversible_command (_("clear ranges"));
2476 XMLNode &before = _session->locations()->get_state();
2478 _session->locations()->clear_ranges ();
2480 XMLNode &after = _session->locations()->get_state();
2481 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2483 commit_reversible_command ();
2488 Editor::clear_locations ()
2490 begin_reversible_command (_("clear locations"));
2492 XMLNode &before = _session->locations()->get_state();
2493 _session->locations()->clear ();
2494 XMLNode &after = _session->locations()->get_state();
2495 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2497 commit_reversible_command ();
2501 Editor::unhide_markers ()
2503 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2504 Location *l = (*i).first;
2505 if (l->is_hidden() && l->is_mark()) {
2506 l->set_hidden(false, this);
2512 Editor::unhide_ranges ()
2514 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2515 Location *l = (*i).first;
2516 if (l->is_hidden() && l->is_range_marker()) {
2517 l->set_hidden(false, this);
2522 /* INSERT/REPLACE */
2525 Editor::insert_region_list_selection (float times)
2527 RouteTimeAxisView *tv = 0;
2528 boost::shared_ptr<Playlist> playlist;
2530 if (clicked_routeview != 0) {
2531 tv = clicked_routeview;
2532 } else if (!selection->tracks.empty()) {
2533 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2536 } else if (entered_track != 0) {
2537 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2544 if ((playlist = tv->playlist()) == 0) {
2548 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2553 begin_reversible_command (_("insert region"));
2554 playlist->clear_changes ();
2555 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2556 if (Config->get_edit_mode() == Ripple)
2557 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2559 _session->add_command(new StatefulDiffCommand (playlist));
2560 commit_reversible_command ();
2563 /* BUILT-IN EFFECTS */
2566 Editor::reverse_selection ()
2571 /* GAIN ENVELOPE EDITING */
2574 Editor::edit_envelope ()
2581 Editor::transition_to_rolling (bool fwd)
2587 if (_session->config.get_external_sync()) {
2588 switch (Config->get_sync_source()) {
2592 /* transport controlled by the master */
2597 if (_session->is_auditioning()) {
2598 _session->cancel_audition ();
2602 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2606 Editor::play_from_start ()
2608 _session->request_locate (_session->current_start_frame(), true);
2612 Editor::play_from_edit_point ()
2614 _session->request_locate (get_preferred_edit_position(), true);
2618 Editor::play_from_edit_point_and_return ()
2620 framepos_t start_frame;
2621 framepos_t return_frame;
2623 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2625 if (_session->transport_rolling()) {
2626 _session->request_locate (start_frame, false);
2630 /* don't reset the return frame if its already set */
2632 if ((return_frame = _session->requested_return_frame()) < 0) {
2633 return_frame = _session->audible_frame();
2636 if (start_frame >= 0) {
2637 _session->request_roll_at_and_return (start_frame, return_frame);
2642 Editor::play_selection ()
2644 framepos_t start, end;
2645 if (!get_selection_extents ( start, end))
2648 AudioRange ar (start, end, 0);
2649 list<AudioRange> lar;
2652 _session->request_play_range (&lar, true);
2656 Editor::get_preroll ()
2658 return Config->get_preroll_seconds() * _session->frame_rate();
2663 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2665 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2668 location -= get_preroll();
2670 //don't try to locate before the beginning of time
2674 //if follow_playhead is on, keep the playhead on the screen
2675 if ( _follow_playhead )
2676 if ( location < leftmost_frame )
2677 location = leftmost_frame;
2679 _session->request_locate( location );
2683 Editor::play_with_preroll ()
2686 framepos_t preroll = get_preroll();
2688 framepos_t start, end;
2689 if (!get_selection_extents ( start, end))
2692 if (start > preroll)
2693 start = start - preroll;
2695 end = end + preroll; //"post-roll"
2697 AudioRange ar (start, end, 0);
2698 list<AudioRange> lar;
2701 _session->request_play_range (&lar, true);
2706 Editor::play_location (Location& location)
2708 if (location.start() <= location.end()) {
2712 _session->request_bounded_roll (location.start(), location.end());
2716 Editor::loop_location (Location& location)
2718 if (location.start() <= location.end()) {
2724 if ((tll = transport_loop_location()) != 0) {
2725 tll->set (location.start(), location.end());
2727 // enable looping, reposition and start rolling
2728 _session->request_locate (tll->start(), true);
2729 _session->request_play_loop (true);
2734 Editor::do_layer_operation (LayerOperation op)
2736 if (selection->regions.empty ()) {
2740 bool const multiple = selection->regions.size() > 1;
2744 begin_reversible_command (_("raise regions"));
2746 begin_reversible_command (_("raise region"));
2752 begin_reversible_command (_("raise regions to top"));
2754 begin_reversible_command (_("raise region to top"));
2760 begin_reversible_command (_("lower regions"));
2762 begin_reversible_command (_("lower region"));
2768 begin_reversible_command (_("lower regions to bottom"));
2770 begin_reversible_command (_("lower region"));
2775 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2776 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2777 (*i)->clear_owned_changes ();
2780 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2781 boost::shared_ptr<Region> r = (*i)->region ();
2793 r->lower_to_bottom ();
2797 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2798 vector<Command*> cmds;
2800 _session->add_commands (cmds);
2803 commit_reversible_command ();
2807 Editor::raise_region ()
2809 do_layer_operation (Raise);
2813 Editor::raise_region_to_top ()
2815 do_layer_operation (RaiseToTop);
2819 Editor::lower_region ()
2821 do_layer_operation (Lower);
2825 Editor::lower_region_to_bottom ()
2827 do_layer_operation (LowerToBottom);
2830 /** Show the region editor for the selected regions */
2832 Editor::show_region_properties ()
2834 selection->foreach_regionview (&RegionView::show_region_editor);
2837 /** Show the midi list editor for the selected MIDI regions */
2839 Editor::show_midi_list_editor ()
2841 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2845 Editor::rename_region ()
2847 RegionSelection rs = get_regions_from_selection_and_entered ();
2853 ArdourDialog d (_("Rename Region"), true, false);
2855 Label label (_("New name:"));
2858 hbox.set_spacing (6);
2859 hbox.pack_start (label, false, false);
2860 hbox.pack_start (entry, true, true);
2862 d.get_vbox()->set_border_width (12);
2863 d.get_vbox()->pack_start (hbox, false, false);
2865 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2866 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2868 d.set_size_request (300, -1);
2870 entry.set_text (rs.front()->region()->name());
2871 entry.select_region (0, -1);
2873 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2879 int const ret = d.run();
2883 if (ret != RESPONSE_OK) {
2887 std::string str = entry.get_text();
2888 strip_whitespace_edges (str);
2890 rs.front()->region()->set_name (str);
2891 _regions->redisplay ();
2895 /** Start an audition of the first selected region */
2897 Editor::play_edit_range ()
2899 framepos_t start, end;
2901 if (get_edit_op_range (start, end)) {
2902 _session->request_bounded_roll (start, end);
2907 Editor::play_selected_region ()
2909 framepos_t start = max_framepos;
2912 RegionSelection rs = get_regions_from_selection_and_entered ();
2918 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2919 if ((*i)->region()->position() < start) {
2920 start = (*i)->region()->position();
2922 if ((*i)->region()->last_frame() + 1 > end) {
2923 end = (*i)->region()->last_frame() + 1;
2927 _session->request_bounded_roll (start, end);
2931 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2933 _session->audition_region (region);
2937 Editor::region_from_selection ()
2939 if (clicked_axisview == 0) {
2943 if (selection->time.empty()) {
2947 framepos_t start = selection->time[clicked_selection].start;
2948 framepos_t end = selection->time[clicked_selection].end;
2950 TrackViewList tracks = get_tracks_for_range_action ();
2952 framepos_t selection_cnt = end - start + 1;
2954 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2955 boost::shared_ptr<Region> current;
2956 boost::shared_ptr<Playlist> pl;
2957 framepos_t internal_start;
2960 if ((pl = (*i)->playlist()) == 0) {
2964 if ((current = pl->top_region_at (start)) == 0) {
2968 internal_start = start - current->position();
2969 RegionFactory::region_name (new_name, current->name(), true);
2973 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2974 plist.add (ARDOUR::Properties::length, selection_cnt);
2975 plist.add (ARDOUR::Properties::name, new_name);
2976 plist.add (ARDOUR::Properties::layer, 0);
2978 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2983 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2985 if (selection->time.empty() || selection->tracks.empty()) {
2989 framepos_t start, end;
2990 if (clicked_selection) {
2991 start = selection->time[clicked_selection].start;
2992 end = selection->time[clicked_selection].end;
2994 start = selection->time.start();
2995 end = selection->time.end_frame();
2998 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2999 sort_track_selection (ts);
3001 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3002 boost::shared_ptr<Region> current;
3003 boost::shared_ptr<Playlist> playlist;
3004 framepos_t internal_start;
3007 if ((playlist = (*i)->playlist()) == 0) {
3011 if ((current = playlist->top_region_at(start)) == 0) {
3015 internal_start = start - current->position();
3016 RegionFactory::region_name (new_name, current->name(), true);
3020 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3021 plist.add (ARDOUR::Properties::length, end - start + 1);
3022 plist.add (ARDOUR::Properties::name, new_name);
3024 new_regions.push_back (RegionFactory::create (current, plist));
3029 Editor::split_multichannel_region ()
3031 RegionSelection rs = get_regions_from_selection_and_entered ();
3037 vector< boost::shared_ptr<Region> > v;
3039 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3040 (*x)->region()->separate_by_channel (*_session, v);
3045 Editor::new_region_from_selection ()
3047 region_from_selection ();
3048 cancel_selection ();
3052 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3054 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3055 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3056 case Evoral::OverlapNone:
3064 * - selected tracks, or if there are none...
3065 * - tracks containing selected regions, or if there are none...
3070 Editor::get_tracks_for_range_action () const
3074 if (selection->tracks.empty()) {
3076 /* use tracks with selected regions */
3078 RegionSelection rs = selection->regions;
3080 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3081 TimeAxisView* tv = &(*i)->get_time_axis_view();
3083 if (!t.contains (tv)) {
3089 /* no regions and no tracks: use all tracks */
3095 t = selection->tracks;
3098 return t.filter_to_unique_playlists();
3102 Editor::separate_regions_between (const TimeSelection& ts)
3104 bool in_command = false;
3105 boost::shared_ptr<Playlist> playlist;
3106 RegionSelection new_selection;
3108 TrackViewList tmptracks = get_tracks_for_range_action ();
3109 sort_track_selection (tmptracks);
3111 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3113 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3119 if (!rtv->is_track()) {
3123 /* no edits to destructive tracks */
3125 if (rtv->track()->destructive()) {
3129 if ((playlist = rtv->playlist()) != 0) {
3131 playlist->clear_changes ();
3133 /* XXX need to consider musical time selections here at some point */
3135 double speed = rtv->track()->speed();
3137 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3139 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3140 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3142 latest_regionviews.clear ();
3144 playlist->partition ((framepos_t)((*t).start * speed),
3145 (framepos_t)((*t).end * speed), false);
3149 if (!latest_regionviews.empty()) {
3151 rtv->view()->foreach_regionview (sigc::bind (
3152 sigc::ptr_fun (add_if_covered),
3153 &(*t), &new_selection));
3156 begin_reversible_command (_("separate"));
3160 /* pick up changes to existing regions */
3162 vector<Command*> cmds;
3163 playlist->rdiff (cmds);
3164 _session->add_commands (cmds);
3166 /* pick up changes to the playlist itself (adds/removes)
3169 _session->add_command(new StatefulDiffCommand (playlist));
3176 // selection->set (new_selection);
3178 commit_reversible_command ();
3182 struct PlaylistState {
3183 boost::shared_ptr<Playlist> playlist;
3187 /** Take tracks from get_tracks_for_range_action and cut any regions
3188 * on those tracks so that the tracks are empty over the time
3192 Editor::separate_region_from_selection ()
3194 /* preferentially use *all* ranges in the time selection if we're in range mode
3195 to allow discontiguous operation, since get_edit_op_range() currently
3196 returns a single range.
3199 if (!selection->time.empty()) {
3201 separate_regions_between (selection->time);
3208 if (get_edit_op_range (start, end)) {
3210 AudioRange ar (start, end, 1);
3214 separate_regions_between (ts);
3220 Editor::separate_region_from_punch ()
3222 Location* loc = _session->locations()->auto_punch_location();
3224 separate_regions_using_location (*loc);
3229 Editor::separate_region_from_loop ()
3231 Location* loc = _session->locations()->auto_loop_location();
3233 separate_regions_using_location (*loc);
3238 Editor::separate_regions_using_location (Location& loc)
3240 if (loc.is_mark()) {
3244 AudioRange ar (loc.start(), loc.end(), 1);
3249 separate_regions_between (ts);
3252 /** Separate regions under the selected region */
3254 Editor::separate_under_selected_regions ()
3256 vector<PlaylistState> playlists;
3260 rs = get_regions_from_selection_and_entered();
3262 if (!_session || rs.empty()) {
3266 begin_reversible_command (_("separate region under"));
3268 list<boost::shared_ptr<Region> > regions_to_remove;
3270 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3271 // we can't just remove the region(s) in this loop because
3272 // this removes them from the RegionSelection, and they thus
3273 // disappear from underneath the iterator, and the ++i above
3274 // SEGVs in a puzzling fashion.
3276 // so, first iterate over the regions to be removed from rs and
3277 // add them to the regions_to_remove list, and then
3278 // iterate over the list to actually remove them.
3280 regions_to_remove.push_back ((*i)->region());
3283 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3285 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3288 // is this check necessary?
3292 vector<PlaylistState>::iterator i;
3294 //only take state if this is a new playlist.
3295 for (i = playlists.begin(); i != playlists.end(); ++i) {
3296 if ((*i).playlist == playlist) {
3301 if (i == playlists.end()) {
3303 PlaylistState before;
3304 before.playlist = playlist;
3305 before.before = &playlist->get_state();
3307 playlist->freeze ();
3308 playlists.push_back(before);
3311 //Partition on the region bounds
3312 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3314 //Re-add region that was just removed due to the partition operation
3315 playlist->add_region( (*rl), (*rl)->first_frame() );
3318 vector<PlaylistState>::iterator pl;
3320 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3321 (*pl).playlist->thaw ();
3322 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3325 commit_reversible_command ();
3329 Editor::crop_region_to_selection ()
3331 if (!selection->time.empty()) {
3333 crop_region_to (selection->time.start(), selection->time.end_frame());
3340 if (get_edit_op_range (start, end)) {
3341 crop_region_to (start, end);
3348 Editor::crop_region_to (framepos_t start, framepos_t end)
3350 vector<boost::shared_ptr<Playlist> > playlists;
3351 boost::shared_ptr<Playlist> playlist;
3354 if (selection->tracks.empty()) {
3355 ts = track_views.filter_to_unique_playlists();
3357 ts = selection->tracks.filter_to_unique_playlists ();
3360 sort_track_selection (ts);
3362 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3364 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3370 boost::shared_ptr<Track> t = rtv->track();
3372 if (t != 0 && ! t->destructive()) {
3374 if ((playlist = rtv->playlist()) != 0) {
3375 playlists.push_back (playlist);
3380 if (playlists.empty()) {
3385 framepos_t new_start;
3387 framecnt_t new_length;
3388 bool in_command = false;
3390 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3392 /* Only the top regions at start and end have to be cropped */
3393 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3394 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3396 vector<boost::shared_ptr<Region> > regions;
3398 if (region_at_start != 0) {
3399 regions.push_back (region_at_start);
3401 if (region_at_end != 0) {
3402 regions.push_back (region_at_end);
3405 /* now adjust lengths */
3406 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3408 pos = (*i)->position();
3409 new_start = max (start, pos);
3410 if (max_framepos - pos > (*i)->length()) {
3411 new_end = pos + (*i)->length() - 1;
3413 new_end = max_framepos;
3415 new_end = min (end, new_end);
3416 new_length = new_end - new_start + 1;
3419 begin_reversible_command (_("trim to selection"));
3422 (*i)->clear_changes ();
3423 (*i)->trim_to (new_start, new_length);
3424 _session->add_command (new StatefulDiffCommand (*i));
3429 commit_reversible_command ();
3434 Editor::region_fill_track ()
3436 boost::shared_ptr<Playlist> playlist;
3437 RegionSelection regions = get_regions_from_selection_and_entered ();
3438 RegionSelection foo;
3440 framepos_t const end = _session->current_end_frame ();
3442 if (regions.empty () || regions.end_frame () + 1 >= end) {
3446 framepos_t const start_frame = regions.start ();
3447 framepos_t const end_frame = regions.end_frame ();
3448 framecnt_t const gap = end_frame - start_frame + 1;
3450 begin_reversible_command (Operations::region_fill);
3452 selection->clear_regions ();
3454 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3456 boost::shared_ptr<Region> r ((*i)->region());
3458 TimeAxisView& tv = (*i)->get_time_axis_view();
3459 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3460 latest_regionviews.clear ();
3461 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3463 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3464 playlist = (*i)->region()->playlist();
3465 playlist->clear_changes ();
3466 playlist->duplicate_until (r, position, gap, end);
3467 _session->add_command(new StatefulDiffCommand (playlist));
3471 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3475 selection->set (foo);
3478 commit_reversible_command ();
3482 Editor::set_region_sync_position ()
3484 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3488 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3490 bool in_command = false;
3492 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3494 if (!(*r)->region()->covers (where)) {
3498 boost::shared_ptr<Region> region ((*r)->region());
3501 begin_reversible_command (_("set sync point"));
3505 region->clear_changes ();
3506 region->set_sync_position (where);
3507 _session->add_command(new StatefulDiffCommand (region));
3511 commit_reversible_command ();
3515 /** Remove the sync positions of the selection */
3517 Editor::remove_region_sync ()
3519 RegionSelection rs = get_regions_from_selection_and_entered ();
3525 begin_reversible_command (_("remove region sync"));
3527 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3529 (*i)->region()->clear_changes ();
3530 (*i)->region()->clear_sync_position ();
3531 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3534 commit_reversible_command ();
3538 Editor::naturalize_region ()
3540 RegionSelection rs = get_regions_from_selection_and_entered ();
3546 if (rs.size() > 1) {
3547 begin_reversible_command (_("move regions to original position"));
3549 begin_reversible_command (_("move region to original position"));
3552 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3553 (*i)->region()->clear_changes ();
3554 (*i)->region()->move_to_natural_position ();
3555 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3558 commit_reversible_command ();
3562 Editor::align_regions (RegionPoint what)
3564 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3570 begin_reversible_command (_("align selection"));
3572 framepos_t const position = get_preferred_edit_position ();
3574 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3575 align_region_internal ((*i)->region(), what, position);
3578 commit_reversible_command ();
3581 struct RegionSortByTime {
3582 bool operator() (const RegionView* a, const RegionView* b) {
3583 return a->region()->position() < b->region()->position();
3588 Editor::align_regions_relative (RegionPoint point)
3590 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3596 framepos_t const position = get_preferred_edit_position ();
3598 framepos_t distance = 0;
3602 list<RegionView*> sorted;
3603 rs.by_position (sorted);
3605 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3610 if (position > r->position()) {
3611 distance = position - r->position();
3613 distance = r->position() - position;
3619 if (position > r->last_frame()) {
3620 distance = position - r->last_frame();
3621 pos = r->position() + distance;
3623 distance = r->last_frame() - position;
3624 pos = r->position() - distance;
3630 pos = r->adjust_to_sync (position);
3631 if (pos > r->position()) {
3632 distance = pos - r->position();
3634 distance = r->position() - pos;
3640 if (pos == r->position()) {
3644 begin_reversible_command (_("align selection (relative)"));
3646 /* move first one specially */
3648 r->clear_changes ();
3649 r->set_position (pos);
3650 _session->add_command(new StatefulDiffCommand (r));
3652 /* move rest by the same amount */
3656 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3658 boost::shared_ptr<Region> region ((*i)->region());
3660 region->clear_changes ();
3663 region->set_position (region->position() + distance);
3665 region->set_position (region->position() - distance);
3668 _session->add_command(new StatefulDiffCommand (region));
3672 commit_reversible_command ();
3676 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3678 begin_reversible_command (_("align region"));
3679 align_region_internal (region, point, position);
3680 commit_reversible_command ();
3684 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3686 region->clear_changes ();
3690 region->set_position (region->adjust_to_sync (position));
3694 if (position > region->length()) {
3695 region->set_position (position - region->length());
3700 region->set_position (position);
3704 _session->add_command(new StatefulDiffCommand (region));
3708 Editor::trim_region_front ()
3714 Editor::trim_region_back ()
3716 trim_region (false);
3720 Editor::trim_region (bool front)
3722 framepos_t where = get_preferred_edit_position();
3723 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3729 begin_reversible_command (front ? _("trim front") : _("trim back"));
3731 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3732 if (!(*i)->region()->locked()) {
3734 (*i)->region()->clear_changes ();
3737 (*i)->region()->trim_front (where);
3738 maybe_locate_with_edit_preroll ( where );
3740 (*i)->region()->trim_end (where);
3741 maybe_locate_with_edit_preroll ( where );
3744 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3748 commit_reversible_command ();
3751 /** Trim the end of the selected regions to the position of the edit cursor */
3753 Editor::trim_region_to_loop ()
3755 Location* loc = _session->locations()->auto_loop_location();
3759 trim_region_to_location (*loc, _("trim to loop"));
3763 Editor::trim_region_to_punch ()
3765 Location* loc = _session->locations()->auto_punch_location();
3769 trim_region_to_location (*loc, _("trim to punch"));
3773 Editor::trim_region_to_location (const Location& loc, const char* str)
3775 RegionSelection rs = get_regions_from_selection_and_entered ();
3776 bool in_command = false;
3778 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3779 RegionView* rv = (*x);
3781 /* require region to span proposed trim */
3782 switch (rv->region()->coverage (loc.start(), loc.end())) {
3783 case Evoral::OverlapInternal:
3789 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3798 if (tav->track() != 0) {
3799 speed = tav->track()->speed();
3802 start = session_frame_to_track_frame (loc.start(), speed);
3803 end = session_frame_to_track_frame (loc.end(), speed);
3805 rv->region()->clear_changes ();
3806 rv->region()->trim_to (start, (end - start));
3809 begin_reversible_command (str);
3812 _session->add_command(new StatefulDiffCommand (rv->region()));
3816 commit_reversible_command ();
3821 Editor::trim_region_to_previous_region_end ()
3823 return trim_to_region(false);
3827 Editor::trim_region_to_next_region_start ()
3829 return trim_to_region(true);
3833 Editor::trim_to_region(bool forward)
3835 RegionSelection rs = get_regions_from_selection_and_entered ();
3836 bool in_command = false;
3838 boost::shared_ptr<Region> next_region;
3840 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3842 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3848 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3856 if (atav->track() != 0) {
3857 speed = atav->track()->speed();
3861 boost::shared_ptr<Region> region = arv->region();
3862 boost::shared_ptr<Playlist> playlist (region->playlist());
3864 region->clear_changes ();
3868 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3874 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3875 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3879 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3885 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3887 arv->region_changed (ARDOUR::bounds_change);
3891 begin_reversible_command (_("trim to region"));
3894 _session->add_command(new StatefulDiffCommand (region));
3898 commit_reversible_command ();
3903 Editor::unfreeze_route ()
3905 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3909 clicked_routeview->track()->unfreeze ();
3913 Editor::_freeze_thread (void* arg)
3915 return static_cast<Editor*>(arg)->freeze_thread ();
3919 Editor::freeze_thread ()
3921 /* create event pool because we may need to talk to the session */
3922 SessionEvent::create_per_thread_pool ("freeze events", 64);
3923 /* create per-thread buffers for process() tree to use */
3924 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3925 current_interthread_info->done = true;
3930 Editor::freeze_route ()
3936 /* stop transport before we start. this is important */
3938 _session->request_transport_speed (0.0);
3940 /* wait for just a little while, because the above call is asynchronous */
3942 Glib::usleep (250000);
3944 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3948 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3950 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3951 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3953 d.set_title (_("Cannot freeze"));
3958 if (clicked_routeview->track()->has_external_redirects()) {
3959 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"
3960 "Freezing will only process the signal as far as the first send/insert/return."),
3961 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3963 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3964 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3965 d.set_title (_("Freeze Limits"));
3967 int response = d.run ();
3970 case Gtk::RESPONSE_CANCEL:
3977 InterThreadInfo itt;
3978 current_interthread_info = &itt;
3980 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3982 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3984 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3986 while (!itt.done && !itt.cancel) {
3987 gtk_main_iteration ();
3990 pthread_join (itt.thread, 0);
3991 current_interthread_info = 0;
3995 Editor::bounce_range_selection (bool replace, bool enable_processing)
3997 if (selection->time.empty()) {
4001 TrackSelection views = selection->tracks;
4003 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4005 if (enable_processing) {
4007 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4009 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
4011 _("You can't perform this operation because the processing of the signal "
4012 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
4013 "You can do this without processing, which is a different operation.")
4015 d.set_title (_("Cannot bounce"));
4022 framepos_t start = selection->time[clicked_selection].start;
4023 framepos_t end = selection->time[clicked_selection].end;
4024 framepos_t cnt = end - start + 1;
4025 bool in_command = false;
4027 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4029 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4035 boost::shared_ptr<Playlist> playlist;
4037 if ((playlist = rtv->playlist()) == 0) {
4041 InterThreadInfo itt;
4043 playlist->clear_changes ();
4044 playlist->clear_owned_changes ();
4046 boost::shared_ptr<Region> r;
4048 if (enable_processing) {
4049 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4051 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4059 list<AudioRange> ranges;
4060 ranges.push_back (AudioRange (start, start+cnt, 0));
4061 playlist->cut (ranges); // discard result
4062 playlist->add_region (r, start);
4066 begin_reversible_command (_("bounce range"));
4069 vector<Command*> cmds;
4070 playlist->rdiff (cmds);
4071 _session->add_commands (cmds);
4073 _session->add_command (new StatefulDiffCommand (playlist));
4077 commit_reversible_command ();
4081 /** Delete selected regions, automation points or a time range */
4085 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4086 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4087 bool deleted = false;
4088 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4089 deleted = current_mixer_strip->delete_processors ();
4095 /** Cut selected regions, automation points or a time range */
4102 /** Copy selected regions, automation points or a time range */
4110 /** @return true if a Cut, Copy or Clear is possible */
4112 Editor::can_cut_copy () const
4114 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4121 /** Cut, copy or clear selected regions, automation points or a time range.
4122 * @param op Operation (Delete, Cut, Copy or Clear)
4125 Editor::cut_copy (CutCopyOp op)
4127 /* only cancel selection if cut/copy is successful.*/
4133 opname = _("delete");
4142 opname = _("clear");
4146 /* if we're deleting something, and the mouse is still pressed,
4147 the thing we started a drag for will be gone when we release
4148 the mouse button(s). avoid this. see part 2 at the end of
4152 if (op == Delete || op == Cut || op == Clear) {
4153 if (_drags->active ()) {
4158 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4159 cut_buffer->clear ();
4161 if (entered_marker) {
4163 /* cut/delete op while pointing at a marker */
4166 Location* loc = find_location_from_marker (entered_marker, ignored);
4168 if (_session && loc) {
4169 entered_marker = NULL;
4170 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4177 switch (mouse_mode) {
4180 begin_reversible_command (opname + ' ' + X_("MIDI"));
4182 commit_reversible_command ();
4188 bool did_edit = false;
4190 if (!selection->regions.empty() || !selection->points.empty()) {
4191 begin_reversible_command (opname + ' ' + _("objects"));
4194 if (!selection->regions.empty()) {
4195 cut_copy_regions (op, selection->regions);
4197 if (op == Cut || op == Delete) {
4198 selection->clear_regions ();
4202 if (!selection->points.empty()) {
4203 cut_copy_points (op);
4205 if (op == Cut || op == Delete) {
4206 selection->clear_points ();
4209 } else if (selection->time.empty()) {
4210 framepos_t start, end;
4211 /* no time selection, see if we can get an edit range
4214 if (get_edit_op_range (start, end)) {
4215 selection->set (start, end);
4217 } else if (!selection->time.empty()) {
4218 begin_reversible_command (opname + ' ' + _("range"));
4221 cut_copy_ranges (op);
4223 if (op == Cut || op == Delete) {
4224 selection->clear_time ();
4229 /* reset repeated paste state */
4232 commit_reversible_command ();
4235 if (op == Delete || op == Cut || op == Clear) {
4241 struct AutomationRecord {
4242 AutomationRecord () : state (0) , line(NULL) {}
4243 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4245 XMLNode* state; ///< state before any operation
4246 const AutomationLine* line; ///< line this came from
4247 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4249 struct PointsSelectionPositionSorter {
4250 bool operator() (ControlPoint* a, ControlPoint* b) {
4251 return (*(a->model()))->when < (*(b->model()))->when;
4254 /** Cut, copy or clear selected automation points.
4255 * @param op Operation (Cut, Copy or Clear)
4258 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4260 if (selection->points.empty ()) {
4264 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4265 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4267 /* Keep a record of the AutomationLists that we end up using in this operation */
4268 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4271 /* user could select points in any order */
4272 selection->points.sort(PointsSelectionPositionSorter ());
4274 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4275 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4276 const AutomationLine& line = (*sel_point)->line();
4277 const boost::shared_ptr<AutomationList> al = line.the_list();
4278 if (lists.find (al) == lists.end ()) {
4279 /* We haven't seen this list yet, so make a record for it. This includes
4280 taking a copy of its current state, in case this is needed for undo later.
4282 lists[al] = AutomationRecord (&al->get_state (), &line);
4286 if (op == Cut || op == Copy) {
4287 /* This operation will involve putting things in the cut buffer, so create an empty
4288 ControlList for each of our source lists to put the cut buffer data in.
4290 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4291 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4294 /* Add all selected points to the relevant copy ControlLists */
4295 framepos_t start = std::numeric_limits<framepos_t>::max();
4296 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4297 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4298 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4300 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4302 /* Update earliest MIDI start time in beats */
4303 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4305 /* Update earliest session start time in frames */
4306 start = std::min(start, (*sel_point)->line().session_position(ctrl_evt));
4310 /* Snap start time backwards, so copy/paste is snap aligned. */
4312 if (earliest == Evoral::Beats::max()) {
4313 earliest = Evoral::Beats(); // Weird... don't offset
4315 earliest.round_down_to_beat();
4317 if (start == std::numeric_limits<double>::max()) {
4318 start = 0; // Weird... don't offset
4320 snap_to(start, RoundDownMaybe);
4323 const double line_offset = midi ? earliest.to_double() : start;
4324 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4325 /* Correct this copy list so that it is relative to the earliest
4326 start time, so relative ordering between points is preserved
4327 when copying from several lists and the paste starts at the
4328 earliest copied piece of data. */
4329 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4330 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4331 (*ctrl_evt)->when -= line_offset;
4334 /* And add it to the cut buffer */
4335 cut_buffer->add (al_cpy);
4339 if (op == Delete || op == Cut) {
4340 /* This operation needs to remove things from the main AutomationList, so do that now */
4342 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4343 i->first->freeze ();
4346 /* Remove each selected point from its AutomationList */
4347 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4348 AutomationLine& line = (*sel_point)->line ();
4349 boost::shared_ptr<AutomationList> al = line.the_list();
4353 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4354 /* removing of first and last gain point in region gain lines is prohibited*/
4355 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4361 al->erase ((*sel_point)->model ());
4365 /* Thaw the lists and add undo records for them */
4366 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4367 boost::shared_ptr<AutomationList> al = i->first;
4369 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4374 /** Cut, copy or clear selected automation points.
4375 * @param op Operation (Cut, Copy or Clear)
4378 Editor::cut_copy_midi (CutCopyOp op)
4380 Evoral::Beats earliest = Evoral::Beats::max();
4381 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4382 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4384 if (!mrv->selection().empty()) {
4385 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4387 mrv->cut_copy_clear (op);
4389 /* XXX: not ideal, as there may be more than one track involved in the selection */
4390 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4394 if (!selection->points.empty()) {
4395 cut_copy_points (op, earliest, true);
4396 if (op == Cut || op == Delete) {
4397 selection->clear_points ();
4402 struct lt_playlist {
4403 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4404 return a.playlist < b.playlist;
4408 struct PlaylistMapping {
4410 boost::shared_ptr<Playlist> pl;
4412 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4415 /** Remove `clicked_regionview' */
4417 Editor::remove_clicked_region ()
4419 if (clicked_routeview == 0 || clicked_regionview == 0) {
4423 begin_reversible_command (_("remove region"));
4425 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4427 playlist->clear_changes ();
4428 playlist->clear_owned_changes ();
4429 playlist->remove_region (clicked_regionview->region());
4430 if (Config->get_edit_mode() == Ripple)
4431 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4433 /* We might have removed regions, which alters other regions' layering_index,
4434 so we need to do a recursive diff here.
4436 vector<Command*> cmds;
4437 playlist->rdiff (cmds);
4438 _session->add_commands (cmds);
4440 _session->add_command(new StatefulDiffCommand (playlist));
4441 commit_reversible_command ();
4445 /** Remove the selected regions */
4447 Editor::remove_selected_regions ()
4449 RegionSelection rs = get_regions_from_selection_and_entered ();
4451 if (!_session || rs.empty()) {
4455 list<boost::shared_ptr<Region> > regions_to_remove;
4457 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4458 // we can't just remove the region(s) in this loop because
4459 // this removes them from the RegionSelection, and they thus
4460 // disappear from underneath the iterator, and the ++i above
4461 // SEGVs in a puzzling fashion.
4463 // so, first iterate over the regions to be removed from rs and
4464 // add them to the regions_to_remove list, and then
4465 // iterate over the list to actually remove them.
4467 regions_to_remove.push_back ((*i)->region());
4470 vector<boost::shared_ptr<Playlist> > playlists;
4472 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4474 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4477 // is this check necessary?
4481 /* get_regions_from_selection_and_entered() guarantees that
4482 the playlists involved are unique, so there is no need
4486 playlists.push_back (playlist);
4488 playlist->clear_changes ();
4489 playlist->clear_owned_changes ();
4490 playlist->freeze ();
4491 playlist->remove_region (*rl);
4492 if (Config->get_edit_mode() == Ripple)
4493 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4497 vector<boost::shared_ptr<Playlist> >::iterator pl;
4498 bool in_command = false;
4500 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4503 /* We might have removed regions, which alters other regions' layering_index,
4504 so we need to do a recursive diff here.
4508 begin_reversible_command (_("remove region"));
4511 vector<Command*> cmds;
4512 (*pl)->rdiff (cmds);
4513 _session->add_commands (cmds);
4515 _session->add_command(new StatefulDiffCommand (*pl));
4519 commit_reversible_command ();
4523 /** Cut, copy or clear selected regions.
4524 * @param op Operation (Cut, Copy or Clear)
4527 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4529 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4530 a map when we want ordered access to both elements. i think.
4533 vector<PlaylistMapping> pmap;
4535 framepos_t first_position = max_framepos;
4537 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4538 FreezeList freezelist;
4540 /* get ordering correct before we cut/copy */
4542 rs.sort_by_position_and_track ();
4544 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4546 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4548 if (op == Cut || op == Clear || op == Delete) {
4549 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4552 FreezeList::iterator fl;
4554 // only take state if this is a new playlist.
4555 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4561 if (fl == freezelist.end()) {
4562 pl->clear_changes();
4563 pl->clear_owned_changes ();
4565 freezelist.insert (pl);
4570 TimeAxisView* tv = &(*x)->get_time_axis_view();
4571 vector<PlaylistMapping>::iterator z;
4573 for (z = pmap.begin(); z != pmap.end(); ++z) {
4574 if ((*z).tv == tv) {
4579 if (z == pmap.end()) {
4580 pmap.push_back (PlaylistMapping (tv));
4584 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4586 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4589 /* region not yet associated with a playlist (e.g. unfinished
4596 TimeAxisView& tv = (*x)->get_time_axis_view();
4597 boost::shared_ptr<Playlist> npl;
4598 RegionSelection::iterator tmp;
4605 vector<PlaylistMapping>::iterator z;
4607 for (z = pmap.begin(); z != pmap.end(); ++z) {
4608 if ((*z).tv == &tv) {
4613 assert (z != pmap.end());
4616 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4624 boost::shared_ptr<Region> r = (*x)->region();
4625 boost::shared_ptr<Region> _xx;
4631 pl->remove_region (r);
4632 if (Config->get_edit_mode() == Ripple)
4633 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4637 _xx = RegionFactory::create (r);
4638 npl->add_region (_xx, r->position() - first_position);
4639 pl->remove_region (r);
4640 if (Config->get_edit_mode() == Ripple)
4641 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4645 /* copy region before adding, so we're not putting same object into two different playlists */
4646 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4650 pl->remove_region (r);
4651 if (Config->get_edit_mode() == Ripple)
4652 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4661 list<boost::shared_ptr<Playlist> > foo;
4663 /* the pmap is in the same order as the tracks in which selected regions occurred */
4665 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4668 foo.push_back ((*i).pl);
4673 cut_buffer->set (foo);
4677 _last_cut_copy_source_track = 0;
4679 _last_cut_copy_source_track = pmap.front().tv;
4683 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4686 /* We might have removed regions, which alters other regions' layering_index,
4687 so we need to do a recursive diff here.
4689 vector<Command*> cmds;
4690 (*pl)->rdiff (cmds);
4691 _session->add_commands (cmds);
4693 _session->add_command (new StatefulDiffCommand (*pl));
4698 Editor::cut_copy_ranges (CutCopyOp op)
4700 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4702 /* Sort the track selection now, so that it if is used, the playlists
4703 selected by the calls below to cut_copy_clear are in the order that
4704 their tracks appear in the editor. This makes things like paste
4705 of ranges work properly.
4708 sort_track_selection (ts);
4711 if (!entered_track) {
4714 ts.push_back (entered_track);
4717 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4718 (*i)->cut_copy_clear (*selection, op);
4723 Editor::paste (float times, bool from_context)
4725 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4727 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0));
4731 Editor::mouse_paste ()
4736 if (!mouse_frame (where, ignored)) {
4741 paste_internal (where, 1, get_grid_music_divisions (0));
4745 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4747 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4749 if (cut_buffer->empty(internal_editing())) {
4753 if (position == max_framepos) {
4754 position = get_preferred_edit_position();
4755 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4758 if (position == last_paste_pos) {
4759 /* repeated paste in the same position */
4762 /* paste in new location, reset repeated paste state */
4764 last_paste_pos = position;
4767 /* get everything in the correct order */
4770 if (!selection->tracks.empty()) {
4771 /* If there is a track selection, paste into exactly those tracks and
4772 only those tracks. This allows the user to be explicit and override
4773 the below "do the reasonable thing" logic. */
4774 ts = selection->tracks.filter_to_unique_playlists ();
4775 sort_track_selection (ts);
4777 /* Figure out which track to base the paste at. */
4778 TimeAxisView* base_track = NULL;
4779 if (_edit_point == Editing::EditAtMouse && entered_track) {
4780 /* With the mouse edit point, paste onto the track under the mouse. */
4781 base_track = entered_track;
4782 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4783 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4784 base_track = &entered_regionview->get_time_axis_view();
4785 } else if (_last_cut_copy_source_track) {
4786 /* Paste to the track that the cut/copy came from (see mantis #333). */
4787 base_track = _last_cut_copy_source_track;
4789 /* This is "impossible" since we've copied... well, do nothing. */
4793 /* Walk up to parent if necessary, so base track is a route. */
4794 while (base_track->get_parent()) {
4795 base_track = base_track->get_parent();
4798 /* Add base track and all tracks below it. The paste logic will select
4799 the appropriate object types from the cut buffer in relative order. */
4800 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4801 if ((*i)->order() >= base_track->order()) {
4806 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4807 sort_track_selection (ts);
4809 /* Add automation children of each track in order, for pasting several lines. */
4810 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4811 /* Add any automation children for pasting several lines */
4812 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4817 typedef RouteTimeAxisView::AutomationTracks ATracks;
4818 const ATracks& atracks = rtv->automation_tracks();
4819 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4820 i = ts.insert(i, a->second.get());
4825 /* We now have a list of trackviews starting at base_track, including
4826 automation children, in the order shown in the editor, e.g. R1,
4827 R1.A1, R1.A2, R2, R2.A1, ... */
4830 begin_reversible_command (Operations::paste);
4832 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4833 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4834 /* Only one line copied, and one automation track selected. Do a
4835 "greedy" paste from one automation type to another. */
4837 PasteContext ctx(paste_count, times, ItemCounts(), true);
4838 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4842 /* Paste into tracks */
4844 PasteContext ctx(paste_count, times, ItemCounts(), false);
4845 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4846 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4850 commit_reversible_command ();
4854 Editor::duplicate_regions (float times)
4856 RegionSelection rs (get_regions_from_selection_and_entered());
4857 duplicate_some_regions (rs, times);
4861 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4863 if (regions.empty ()) {
4867 boost::shared_ptr<Playlist> playlist;
4868 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4869 RegionSelection foo;
4871 framepos_t const start_frame = regions.start ();
4872 framepos_t const end_frame = regions.end_frame ();
4873 framecnt_t const gap = end_frame - start_frame + 1;
4875 begin_reversible_command (Operations::duplicate_region);
4877 selection->clear_regions ();
4879 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4881 boost::shared_ptr<Region> r ((*i)->region());
4883 TimeAxisView& tv = (*i)->get_time_axis_view();
4884 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4885 latest_regionviews.clear ();
4886 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4888 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4889 playlist = (*i)->region()->playlist();
4890 playlist->clear_changes ();
4891 playlist->duplicate (r, position, gap, times);
4892 _session->add_command(new StatefulDiffCommand (playlist));
4896 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4900 selection->set (foo);
4903 commit_reversible_command ();
4907 Editor::duplicate_selection (float times)
4909 if (selection->time.empty() || selection->tracks.empty()) {
4913 boost::shared_ptr<Playlist> playlist;
4915 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4917 bool in_command = false;
4919 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4920 if ((playlist = (*i)->playlist()) == 0) {
4923 playlist->clear_changes ();
4925 if (clicked_selection) {
4926 playlist->duplicate_range (selection->time[clicked_selection], times);
4928 playlist->duplicate_ranges (selection->time, times);
4932 begin_reversible_command (_("duplicate range selection"));
4935 _session->add_command (new StatefulDiffCommand (playlist));
4940 // now "move" range selection to after the current range selection
4941 framecnt_t distance = 0;
4943 if (clicked_selection) {
4944 distance = selection->time[clicked_selection].end -
4945 selection->time[clicked_selection].start;
4947 distance = selection->time.end_frame() - selection->time.start();
4950 selection->move_time (distance);
4952 commit_reversible_command ();
4956 /** Reset all selected points to the relevant default value */
4958 Editor::reset_point_selection ()
4960 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4961 ARDOUR::AutomationList::iterator j = (*i)->model ();
4962 (*j)->value = (*i)->line().the_list()->default_value ();
4967 Editor::center_playhead ()
4969 float const page = _visible_canvas_width * samples_per_pixel;
4970 center_screen_internal (playhead_cursor->current_frame (), page);
4974 Editor::center_edit_point ()
4976 float const page = _visible_canvas_width * samples_per_pixel;
4977 center_screen_internal (get_preferred_edit_position(), page);
4980 /** Caller must begin and commit a reversible command */
4982 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4984 playlist->clear_changes ();
4986 _session->add_command (new StatefulDiffCommand (playlist));
4990 Editor::nudge_track (bool use_edit, bool forwards)
4992 boost::shared_ptr<Playlist> playlist;
4993 framepos_t distance;
4994 framepos_t next_distance;
4998 start = get_preferred_edit_position();
5003 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
5007 if (selection->tracks.empty()) {
5011 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5012 bool in_command = false;
5014 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5016 if ((playlist = (*i)->playlist()) == 0) {
5020 playlist->clear_changes ();
5021 playlist->clear_owned_changes ();
5023 playlist->nudge_after (start, distance, forwards);
5026 begin_reversible_command (_("nudge track"));
5029 vector<Command*> cmds;
5031 playlist->rdiff (cmds);
5032 _session->add_commands (cmds);
5034 _session->add_command (new StatefulDiffCommand (playlist));
5038 commit_reversible_command ();
5043 Editor::remove_last_capture ()
5045 vector<string> choices;
5052 if (Config->get_verify_remove_last_capture()) {
5053 prompt = _("Do you really want to destroy the last capture?"
5054 "\n(This is destructive and cannot be undone)");
5056 choices.push_back (_("No, do nothing."));
5057 choices.push_back (_("Yes, destroy it."));
5059 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
5061 if (prompter.run () == 1) {
5062 _session->remove_last_capture ();
5063 _regions->redisplay ();
5067 _session->remove_last_capture();
5068 _regions->redisplay ();
5073 Editor::normalize_region ()
5079 RegionSelection rs = get_regions_from_selection_and_entered ();
5085 NormalizeDialog dialog (rs.size() > 1);
5087 if (dialog.run () != RESPONSE_ACCEPT) {
5091 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5094 /* XXX: should really only count audio regions here */
5095 int const regions = rs.size ();
5097 /* Make a list of the selected audio regions' maximum amplitudes, and also
5098 obtain the maximum amplitude of them all.
5100 list<double> max_amps;
5101 list<double> rms_vals;
5104 bool use_rms = dialog.constrain_rms ();
5106 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5107 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5111 dialog.descend (1.0 / regions);
5112 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5114 double r = arv->audio_region()->rms (&dialog);
5115 max_rms = max (max_rms, r);
5116 rms_vals.push_back (r);
5120 /* the user cancelled the operation */
5124 max_amps.push_back (a);
5125 max_amp = max (max_amp, a);
5129 list<double>::const_iterator a = max_amps.begin ();
5130 list<double>::const_iterator l = rms_vals.begin ();
5131 bool in_command = false;
5133 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5134 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5139 arv->region()->clear_changes ();
5141 double amp = dialog.normalize_individually() ? *a : max_amp;
5142 double target = dialog.target_peak (); // dB
5145 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5146 const double t_rms = dialog.target_rms ();
5147 const gain_t c_peak = dB_to_coefficient (target);
5148 const gain_t c_rms = dB_to_coefficient (t_rms);
5149 if ((amp_rms / c_rms) > (amp / c_peak)) {
5155 arv->audio_region()->normalize (amp, target);
5158 begin_reversible_command (_("normalize"));
5161 _session->add_command (new StatefulDiffCommand (arv->region()));
5168 commit_reversible_command ();
5174 Editor::reset_region_scale_amplitude ()
5180 RegionSelection rs = get_regions_from_selection_and_entered ();
5186 bool in_command = false;
5188 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5189 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5192 arv->region()->clear_changes ();
5193 arv->audio_region()->set_scale_amplitude (1.0f);
5196 begin_reversible_command ("reset gain");
5199 _session->add_command (new StatefulDiffCommand (arv->region()));
5203 commit_reversible_command ();
5208 Editor::adjust_region_gain (bool up)
5210 RegionSelection rs = get_regions_from_selection_and_entered ();
5212 if (!_session || rs.empty()) {
5216 bool in_command = false;
5218 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5219 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5224 arv->region()->clear_changes ();
5226 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5234 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5237 begin_reversible_command ("adjust region gain");
5240 _session->add_command (new StatefulDiffCommand (arv->region()));
5244 commit_reversible_command ();
5250 Editor::reverse_region ()
5256 Reverse rev (*_session);
5257 apply_filter (rev, _("reverse regions"));
5261 Editor::strip_region_silence ()
5267 RegionSelection rs = get_regions_from_selection_and_entered ();
5273 std::list<RegionView*> audio_only;
5275 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5276 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5278 audio_only.push_back (arv);
5282 assert (!audio_only.empty());
5284 StripSilenceDialog d (_session, audio_only);
5285 int const r = d.run ();
5289 if (r == Gtk::RESPONSE_OK) {
5290 ARDOUR::AudioIntervalMap silences;
5291 d.silences (silences);
5292 StripSilence s (*_session, silences, d.fade_length());
5294 apply_filter (s, _("strip silence"), &d);
5299 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5301 Evoral::Sequence<Evoral::Beats>::Notes selected;
5302 mrv.selection_as_notelist (selected, true);
5304 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5305 v.push_back (selected);
5307 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5309 return op (mrv.midi_region()->model(), pos_beats, v);
5313 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5319 bool in_command = false;
5321 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5322 RegionSelection::const_iterator tmp = r;
5325 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5328 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5331 begin_reversible_command (op.name ());
5335 _session->add_command (cmd);
5343 commit_reversible_command ();
5348 Editor::fork_region ()
5350 RegionSelection rs = get_regions_from_selection_and_entered ();
5356 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5357 bool in_command = false;
5361 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5362 RegionSelection::iterator tmp = r;
5365 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5369 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5370 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5371 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5374 begin_reversible_command (_("Fork Region(s)"));
5377 playlist->clear_changes ();
5378 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5379 _session->add_command(new StatefulDiffCommand (playlist));
5381 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5389 commit_reversible_command ();
5394 Editor::quantize_region ()
5397 quantize_regions(get_regions_from_selection_and_entered ());
5402 Editor::quantize_regions (const RegionSelection& rs)
5404 if (rs.n_midi_regions() == 0) {
5408 if (!quantize_dialog) {
5409 quantize_dialog = new QuantizeDialog (*this);
5412 if (quantize_dialog->is_mapped()) {
5413 /* in progress already */
5417 quantize_dialog->present ();
5418 const int r = quantize_dialog->run ();
5419 quantize_dialog->hide ();
5421 if (r == Gtk::RESPONSE_OK) {
5422 Quantize quant (quantize_dialog->snap_start(),
5423 quantize_dialog->snap_end(),
5424 quantize_dialog->start_grid_size(),
5425 quantize_dialog->end_grid_size(),
5426 quantize_dialog->strength(),
5427 quantize_dialog->swing(),
5428 quantize_dialog->threshold());
5430 apply_midi_note_edit_op (quant, rs);
5435 Editor::legatize_region (bool shrink_only)
5438 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5443 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5445 if (rs.n_midi_regions() == 0) {
5449 Legatize legatize(shrink_only);
5450 apply_midi_note_edit_op (legatize, rs);
5454 Editor::transform_region ()
5457 transform_regions(get_regions_from_selection_and_entered ());
5462 Editor::transform_regions (const RegionSelection& rs)
5464 if (rs.n_midi_regions() == 0) {
5471 const int r = td.run();
5474 if (r == Gtk::RESPONSE_OK) {
5475 Transform transform(td.get());
5476 apply_midi_note_edit_op(transform, rs);
5481 Editor::transpose_region ()
5484 transpose_regions(get_regions_from_selection_and_entered ());
5489 Editor::transpose_regions (const RegionSelection& rs)
5491 if (rs.n_midi_regions() == 0) {
5496 int const r = d.run ();
5498 if (r == RESPONSE_ACCEPT) {
5499 Transpose transpose(d.semitones ());
5500 apply_midi_note_edit_op (transpose, rs);
5505 Editor::insert_patch_change (bool from_context)
5507 RegionSelection rs = get_regions_from_selection_and_entered ();
5513 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5515 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5516 there may be more than one, but the PatchChangeDialog can only offer
5517 one set of patch menus.
5519 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5521 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5522 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5524 if (d.run() == RESPONSE_CANCEL) {
5528 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5529 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5531 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5532 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5539 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5541 RegionSelection rs = get_regions_from_selection_and_entered ();
5547 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5548 bool in_command = false;
5553 int const N = rs.size ();
5555 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5556 RegionSelection::iterator tmp = r;
5559 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5561 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5564 progress->descend (1.0 / N);
5567 if (arv->audio_region()->apply (filter, progress) == 0) {
5569 playlist->clear_changes ();
5570 playlist->clear_owned_changes ();
5573 begin_reversible_command (command);
5577 if (filter.results.empty ()) {
5579 /* no regions returned; remove the old one */
5580 playlist->remove_region (arv->region ());
5584 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5586 /* first region replaces the old one */
5587 playlist->replace_region (arv->region(), *res, (*res)->position());
5591 while (res != filter.results.end()) {
5592 playlist->add_region (*res, (*res)->position());
5598 /* We might have removed regions, which alters other regions' layering_index,
5599 so we need to do a recursive diff here.
5601 vector<Command*> cmds;
5602 playlist->rdiff (cmds);
5603 _session->add_commands (cmds);
5605 _session->add_command(new StatefulDiffCommand (playlist));
5609 progress->ascend ();
5618 commit_reversible_command ();
5623 Editor::external_edit_region ()
5629 Editor::reset_region_gain_envelopes ()
5631 RegionSelection rs = get_regions_from_selection_and_entered ();
5633 if (!_session || rs.empty()) {
5637 bool in_command = false;
5639 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5640 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5642 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5643 XMLNode& before (alist->get_state());
5645 arv->audio_region()->set_default_envelope ();
5648 begin_reversible_command (_("reset region gain"));
5651 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5656 commit_reversible_command ();
5661 Editor::set_region_gain_visibility (RegionView* rv)
5663 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5665 arv->update_envelope_visibility();
5670 Editor::set_gain_envelope_visibility ()
5676 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5677 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5679 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5685 Editor::toggle_gain_envelope_active ()
5687 if (_ignore_region_action) {
5691 RegionSelection rs = get_regions_from_selection_and_entered ();
5693 if (!_session || rs.empty()) {
5697 bool in_command = false;
5699 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5700 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5702 arv->region()->clear_changes ();
5703 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5706 begin_reversible_command (_("region gain envelope active"));
5709 _session->add_command (new StatefulDiffCommand (arv->region()));
5714 commit_reversible_command ();
5719 Editor::toggle_region_lock ()
5721 if (_ignore_region_action) {
5725 RegionSelection rs = get_regions_from_selection_and_entered ();
5727 if (!_session || rs.empty()) {
5731 begin_reversible_command (_("toggle region lock"));
5733 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5734 (*i)->region()->clear_changes ();
5735 (*i)->region()->set_locked (!(*i)->region()->locked());
5736 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5739 commit_reversible_command ();
5743 Editor::toggle_region_video_lock ()
5745 if (_ignore_region_action) {
5749 RegionSelection rs = get_regions_from_selection_and_entered ();
5751 if (!_session || rs.empty()) {
5755 begin_reversible_command (_("Toggle Video Lock"));
5757 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5758 (*i)->region()->clear_changes ();
5759 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5760 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5763 commit_reversible_command ();
5767 Editor::toggle_region_lock_style ()
5769 if (_ignore_region_action) {
5773 RegionSelection rs = get_regions_from_selection_and_entered ();
5775 if (!_session || rs.empty()) {
5779 begin_reversible_command (_("region lock style"));
5781 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5782 (*i)->region()->clear_changes ();
5783 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5784 (*i)->region()->set_position_lock_style (ns);
5785 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5788 commit_reversible_command ();
5792 Editor::toggle_opaque_region ()
5794 if (_ignore_region_action) {
5798 RegionSelection rs = get_regions_from_selection_and_entered ();
5800 if (!_session || rs.empty()) {
5804 begin_reversible_command (_("change region opacity"));
5806 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5807 (*i)->region()->clear_changes ();
5808 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5809 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5812 commit_reversible_command ();
5816 Editor::toggle_record_enable ()
5818 bool new_state = false;
5820 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5821 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5824 if (!rtav->is_track())
5828 new_state = !rtav->track()->rec_enable_control()->get_value();
5832 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5837 Editor::toggle_solo ()
5839 bool new_state = false;
5841 boost::shared_ptr<ControlList> cl (new ControlList);
5843 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5844 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5851 new_state = !rtav->route()->soloed ();
5855 cl->push_back (rtav->route()->solo_control());
5858 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5862 Editor::toggle_mute ()
5864 bool new_state = false;
5866 boost::shared_ptr<RouteList> rl (new RouteList);
5868 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5869 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5876 new_state = !rtav->route()->muted();
5880 rl->push_back (rtav->route());
5883 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5887 Editor::toggle_solo_isolate ()
5893 Editor::fade_range ()
5895 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5897 begin_reversible_command (_("fade range"));
5899 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5900 (*i)->fade_range (selection->time);
5903 commit_reversible_command ();
5908 Editor::set_fade_length (bool in)
5910 RegionSelection rs = get_regions_from_selection_and_entered ();
5916 /* we need a region to measure the offset from the start */
5918 RegionView* rv = rs.front ();
5920 framepos_t pos = get_preferred_edit_position();
5924 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5925 /* edit point is outside the relevant region */
5930 if (pos <= rv->region()->position()) {
5934 len = pos - rv->region()->position();
5935 cmd = _("set fade in length");
5937 if (pos >= rv->region()->last_frame()) {
5941 len = rv->region()->last_frame() - pos;
5942 cmd = _("set fade out length");
5945 bool in_command = false;
5947 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5948 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5954 boost::shared_ptr<AutomationList> alist;
5956 alist = tmp->audio_region()->fade_in();
5958 alist = tmp->audio_region()->fade_out();
5961 XMLNode &before = alist->get_state();
5964 tmp->audio_region()->set_fade_in_length (len);
5965 tmp->audio_region()->set_fade_in_active (true);
5967 tmp->audio_region()->set_fade_out_length (len);
5968 tmp->audio_region()->set_fade_out_active (true);
5972 begin_reversible_command (cmd);
5975 XMLNode &after = alist->get_state();
5976 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5980 commit_reversible_command ();
5985 Editor::set_fade_in_shape (FadeShape shape)
5987 RegionSelection rs = get_regions_from_selection_and_entered ();
5992 bool in_command = false;
5994 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5995 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6001 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
6002 XMLNode &before = alist->get_state();
6004 tmp->audio_region()->set_fade_in_shape (shape);
6007 begin_reversible_command (_("set fade in shape"));
6010 XMLNode &after = alist->get_state();
6011 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6015 commit_reversible_command ();
6020 Editor::set_fade_out_shape (FadeShape shape)
6022 RegionSelection rs = get_regions_from_selection_and_entered ();
6027 bool in_command = false;
6029 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6030 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6036 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6037 XMLNode &before = alist->get_state();
6039 tmp->audio_region()->set_fade_out_shape (shape);
6042 begin_reversible_command (_("set fade out shape"));
6045 XMLNode &after = alist->get_state();
6046 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6050 commit_reversible_command ();
6055 Editor::set_fade_in_active (bool yn)
6057 RegionSelection rs = get_regions_from_selection_and_entered ();
6062 bool in_command = false;
6064 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6065 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6072 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6074 ar->clear_changes ();
6075 ar->set_fade_in_active (yn);
6078 begin_reversible_command (_("set fade in active"));
6081 _session->add_command (new StatefulDiffCommand (ar));
6085 commit_reversible_command ();
6090 Editor::set_fade_out_active (bool yn)
6092 RegionSelection rs = get_regions_from_selection_and_entered ();
6097 bool in_command = false;
6099 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6100 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6106 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6108 ar->clear_changes ();
6109 ar->set_fade_out_active (yn);
6112 begin_reversible_command (_("set fade out active"));
6115 _session->add_command(new StatefulDiffCommand (ar));
6119 commit_reversible_command ();
6124 Editor::toggle_region_fades (int dir)
6126 if (_ignore_region_action) {
6130 boost::shared_ptr<AudioRegion> ar;
6133 RegionSelection rs = get_regions_from_selection_and_entered ();
6139 RegionSelection::iterator i;
6140 for (i = rs.begin(); i != rs.end(); ++i) {
6141 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6143 yn = ar->fade_out_active ();
6145 yn = ar->fade_in_active ();
6151 if (i == rs.end()) {
6155 /* XXX should this undo-able? */
6156 bool in_command = false;
6158 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6159 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6162 ar->clear_changes ();
6164 if (dir == 1 || dir == 0) {
6165 ar->set_fade_in_active (!yn);
6168 if (dir == -1 || dir == 0) {
6169 ar->set_fade_out_active (!yn);
6172 begin_reversible_command (_("toggle fade active"));
6175 _session->add_command(new StatefulDiffCommand (ar));
6179 commit_reversible_command ();
6184 /** Update region fade visibility after its configuration has been changed */
6186 Editor::update_region_fade_visibility ()
6188 bool _fade_visibility = _session->config.get_show_region_fades ();
6190 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6191 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6193 if (_fade_visibility) {
6194 v->audio_view()->show_all_fades ();
6196 v->audio_view()->hide_all_fades ();
6203 Editor::set_edit_point ()
6208 if (!mouse_frame (where, ignored)) {
6214 if (selection->markers.empty()) {
6216 mouse_add_new_marker (where);
6221 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6224 loc->move_to (where);
6230 Editor::set_playhead_cursor ()
6232 if (entered_marker) {
6233 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6238 if (!mouse_frame (where, ignored)) {
6245 _session->request_locate (where, _session->transport_rolling());
6249 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6250 cancel_time_selection();
6255 Editor::split_region ()
6257 if (_drags->active ()) {
6261 //if a range is selected, separate it
6262 if ( !selection->time.empty()) {
6263 separate_regions_between (selection->time);
6267 //if no range was selected, try to find some regions to split
6268 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6270 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6272 framepos_t where = get_preferred_edit_position ();
6278 if (snap_musical()) {
6279 split_regions_at (where, rs, get_grid_music_divisions (0));
6281 split_regions_at (where, rs, 0);
6287 Editor::select_next_route()
6289 if (selection->tracks.empty()) {
6290 selection->set (track_views.front());
6294 TimeAxisView* current = selection->tracks.front();
6298 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6300 if (*i == current) {
6302 if (i != track_views.end()) {
6305 current = (*(track_views.begin()));
6306 //selection->set (*(track_views.begin()));
6312 rui = dynamic_cast<RouteUI *>(current);
6314 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6316 selection->set (current);
6318 ensure_time_axis_view_is_visible (*current, false);
6322 Editor::select_prev_route()
6324 if (selection->tracks.empty()) {
6325 selection->set (track_views.front());
6329 TimeAxisView* current = selection->tracks.front();
6333 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6335 if (*i == current) {
6337 if (i != track_views.rend()) {
6340 current = *(track_views.rbegin());
6345 rui = dynamic_cast<RouteUI *>(current);
6347 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6349 selection->set (current);
6351 ensure_time_axis_view_is_visible (*current, false);
6355 Editor::set_loop_from_selection (bool play)
6357 if (_session == 0) {
6361 framepos_t start, end;
6362 if (!get_selection_extents ( start, end))
6365 set_loop_range (start, end, _("set loop range from selection"));
6368 _session->request_play_loop (true, true);
6373 Editor::set_loop_from_region (bool play)
6375 framepos_t start, end;
6376 if (!get_selection_extents ( start, end))
6379 set_loop_range (start, end, _("set loop range from region"));
6382 _session->request_locate (start, true);
6383 _session->request_play_loop (true);
6388 Editor::set_punch_from_selection ()
6390 if (_session == 0) {
6394 framepos_t start, end;
6395 if (!get_selection_extents ( start, end))
6398 set_punch_range (start, end, _("set punch range from selection"));
6402 Editor::set_auto_punch_range ()
6404 // auto punch in/out button from a single button
6405 // If Punch In is unset, set punch range from playhead to end, enable punch in
6406 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6407 // rewound beyond the Punch In marker, in which case that marker will be moved back
6408 // to the current playhead position.
6409 // If punch out is set, it clears the punch range and Punch In/Out buttons
6411 if (_session == 0) {
6415 Location* tpl = transport_punch_location();
6416 framepos_t now = playhead_cursor->current_frame();
6417 framepos_t begin = now;
6418 framepos_t end = _session->current_end_frame();
6420 if (!_session->config.get_punch_in()) {
6421 // First Press - set punch in and create range from here to eternity
6422 set_punch_range (begin, end, _("Auto Punch In"));
6423 _session->config.set_punch_in(true);
6424 } else if (tpl && !_session->config.get_punch_out()) {
6425 // Second press - update end range marker and set punch_out
6426 if (now < tpl->start()) {
6427 // playhead has been rewound - move start back and pretend nothing happened
6429 set_punch_range (begin, end, _("Auto Punch In/Out"));
6431 // normal case for 2nd press - set the punch out
6432 end = playhead_cursor->current_frame ();
6433 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6434 _session->config.set_punch_out(true);
6437 if (_session->config.get_punch_out()) {
6438 _session->config.set_punch_out(false);
6441 if (_session->config.get_punch_in()) {
6442 _session->config.set_punch_in(false);
6447 // third press - unset punch in/out and remove range
6448 _session->locations()->remove(tpl);
6455 Editor::set_session_extents_from_selection ()
6457 if (_session == 0) {
6461 framepos_t start, end;
6462 if (!get_selection_extents ( start, end))
6466 if ((loc = _session->locations()->session_range_location()) == 0) {
6467 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6469 XMLNode &before = loc->get_state();
6471 _session->set_session_extents (start, end);
6473 XMLNode &after = loc->get_state();
6475 begin_reversible_command (_("set session start/end from selection"));
6477 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6479 commit_reversible_command ();
6482 _session->set_end_is_free (false);
6486 Editor::set_punch_start_from_edit_point ()
6490 framepos_t start = 0;
6491 framepos_t end = max_framepos;
6493 //use the existing punch end, if any
6494 Location* tpl = transport_punch_location();
6499 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6500 start = _session->audible_frame();
6502 start = get_preferred_edit_position();
6505 //snap the selection start/end
6508 //if there's not already a sensible selection endpoint, go "forever"
6509 if ( start > end ) {
6513 set_punch_range (start, end, _("set punch start from EP"));
6519 Editor::set_punch_end_from_edit_point ()
6523 framepos_t start = 0;
6524 framepos_t end = max_framepos;
6526 //use the existing punch start, if any
6527 Location* tpl = transport_punch_location();
6529 start = tpl->start();
6532 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6533 end = _session->audible_frame();
6535 end = get_preferred_edit_position();
6538 //snap the selection start/end
6541 set_punch_range (start, end, _("set punch end from EP"));
6547 Editor::set_loop_start_from_edit_point ()
6551 framepos_t start = 0;
6552 framepos_t end = max_framepos;
6554 //use the existing loop end, if any
6555 Location* tpl = transport_loop_location();
6560 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6561 start = _session->audible_frame();
6563 start = get_preferred_edit_position();
6566 //snap the selection start/end
6569 //if there's not already a sensible selection endpoint, go "forever"
6570 if ( start > end ) {
6574 set_loop_range (start, end, _("set loop start from EP"));
6580 Editor::set_loop_end_from_edit_point ()
6584 framepos_t start = 0;
6585 framepos_t end = max_framepos;
6587 //use the existing loop start, if any
6588 Location* tpl = transport_loop_location();
6590 start = tpl->start();
6593 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6594 end = _session->audible_frame();
6596 end = get_preferred_edit_position();
6599 //snap the selection start/end
6602 set_loop_range (start, end, _("set loop end from EP"));
6607 Editor::set_punch_from_region ()
6609 framepos_t start, end;
6610 if (!get_selection_extents ( start, end))
6613 set_punch_range (start, end, _("set punch range from region"));
6617 Editor::pitch_shift_region ()
6619 RegionSelection rs = get_regions_from_selection_and_entered ();
6621 RegionSelection audio_rs;
6622 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6623 if (dynamic_cast<AudioRegionView*> (*i)) {
6624 audio_rs.push_back (*i);
6628 if (audio_rs.empty()) {
6632 pitch_shift (audio_rs, 1.2);
6636 Editor::set_tempo_from_region ()
6638 RegionSelection rs = get_regions_from_selection_and_entered ();
6640 if (!_session || rs.empty()) {
6644 RegionView* rv = rs.front();
6646 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6650 Editor::use_range_as_bar ()
6652 framepos_t start, end;
6653 if (get_edit_op_range (start, end)) {
6654 define_one_bar (start, end);
6659 Editor::define_one_bar (framepos_t start, framepos_t end)
6661 framepos_t length = end - start;
6663 const Meter& m (_session->tempo_map().meter_at_frame (start));
6665 /* length = 1 bar */
6667 /* We're going to deliver a constant tempo here,
6668 so we can use frames per beat to determine length.
6669 now we want frames per beat.
6670 we have frames per bar, and beats per bar, so ...
6673 /* XXXX METER MATH */
6675 double frames_per_beat = length / m.divisions_per_bar();
6677 /* beats per minute = */
6679 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6681 /* now decide whether to:
6683 (a) set global tempo
6684 (b) add a new tempo marker
6688 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6690 bool do_global = false;
6692 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6694 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6695 at the start, or create a new marker
6698 vector<string> options;
6699 options.push_back (_("Cancel"));
6700 options.push_back (_("Add new marker"));
6701 options.push_back (_("Set global tempo"));
6704 _("Define one bar"),
6705 _("Do you want to set the global tempo or add a new tempo marker?"),
6709 c.set_default_response (2);
6725 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6726 if the marker is at the region starter, change it, otherwise add
6731 begin_reversible_command (_("set tempo from region"));
6732 XMLNode& before (_session->tempo_map().get_state());
6735 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6736 } else if (t.frame() == start) {
6737 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6739 const Tempo tempo (beats_per_minute, t.note_type());
6740 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6743 XMLNode& after (_session->tempo_map().get_state());
6745 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6746 commit_reversible_command ();
6750 Editor::split_region_at_transients ()
6752 AnalysisFeatureList positions;
6754 RegionSelection rs = get_regions_from_selection_and_entered ();
6756 if (!_session || rs.empty()) {
6760 begin_reversible_command (_("split regions"));
6762 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6764 RegionSelection::iterator tmp;
6769 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6772 ar->transients (positions);
6773 split_region_at_points ((*i)->region(), positions, true);
6780 commit_reversible_command ();
6785 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6787 bool use_rhythmic_rodent = false;
6789 boost::shared_ptr<Playlist> pl = r->playlist();
6791 list<boost::shared_ptr<Region> > new_regions;
6797 if (positions.empty()) {
6801 if (positions.size() > 20 && can_ferret) {
6802 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);
6803 MessageDialog msg (msgstr,
6806 Gtk::BUTTONS_OK_CANCEL);
6809 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6810 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6812 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6815 msg.set_title (_("Excessive split?"));
6818 int response = msg.run();
6824 case RESPONSE_APPLY:
6825 use_rhythmic_rodent = true;
6832 if (use_rhythmic_rodent) {
6833 show_rhythm_ferret ();
6837 AnalysisFeatureList::const_iterator x;
6839 pl->clear_changes ();
6840 pl->clear_owned_changes ();
6842 x = positions.begin();
6844 if (x == positions.end()) {
6849 pl->remove_region (r);
6853 framepos_t rstart = r->first_frame ();
6854 framepos_t rend = r->last_frame ();
6856 while (x != positions.end()) {
6858 /* deal with positons that are out of scope of present region bounds */
6859 if (*x <= rstart || *x > rend) {
6864 /* file start = original start + how far we from the initial position ? */
6866 framepos_t file_start = r->start() + pos;
6868 /* length = next position - current position */
6870 framepos_t len = (*x) - pos - rstart;
6872 /* XXX we do we really want to allow even single-sample regions?
6873 * shouldn't we have some kind of lower limit on region size?
6882 if (RegionFactory::region_name (new_name, r->name())) {
6886 /* do NOT announce new regions 1 by one, just wait till they are all done */
6890 plist.add (ARDOUR::Properties::start, file_start);
6891 plist.add (ARDOUR::Properties::length, len);
6892 plist.add (ARDOUR::Properties::name, new_name);
6893 plist.add (ARDOUR::Properties::layer, 0);
6894 // TODO set transients_offset
6896 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6897 /* because we set annouce to false, manually add the new region to the
6900 RegionFactory::map_add (nr);
6902 pl->add_region (nr, rstart + pos);
6905 new_regions.push_front(nr);
6914 RegionFactory::region_name (new_name, r->name());
6916 /* Add the final region */
6919 plist.add (ARDOUR::Properties::start, r->start() + pos);
6920 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6921 plist.add (ARDOUR::Properties::name, new_name);
6922 plist.add (ARDOUR::Properties::layer, 0);
6924 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6925 /* because we set annouce to false, manually add the new region to the
6928 RegionFactory::map_add (nr);
6929 pl->add_region (nr, r->position() + pos);
6932 new_regions.push_front(nr);
6937 /* We might have removed regions, which alters other regions' layering_index,
6938 so we need to do a recursive diff here.
6940 vector<Command*> cmds;
6942 _session->add_commands (cmds);
6944 _session->add_command (new StatefulDiffCommand (pl));
6948 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6949 set_selected_regionview_from_region_list ((*i), Selection::Add);
6955 Editor::place_transient()
6961 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6967 framepos_t where = get_preferred_edit_position();
6969 begin_reversible_command (_("place transient"));
6971 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6972 (*r)->region()->add_transient(where);
6975 commit_reversible_command ();
6979 Editor::remove_transient(ArdourCanvas::Item* item)
6985 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6988 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6989 _arv->remove_transient (*(float*) _line->get_data ("position"));
6993 Editor::snap_regions_to_grid ()
6995 list <boost::shared_ptr<Playlist > > used_playlists;
6997 RegionSelection rs = get_regions_from_selection_and_entered ();
6999 if (!_session || rs.empty()) {
7003 begin_reversible_command (_("snap regions to grid"));
7005 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7007 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7009 if (!pl->frozen()) {
7010 /* we haven't seen this playlist before */
7012 /* remember used playlists so we can thaw them later */
7013 used_playlists.push_back(pl);
7017 framepos_t start_frame = (*r)->region()->first_frame ();
7018 snap_to (start_frame);
7019 (*r)->region()->set_position (start_frame);
7022 while (used_playlists.size() > 0) {
7023 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7025 used_playlists.pop_front();
7028 commit_reversible_command ();
7032 Editor::close_region_gaps ()
7034 list <boost::shared_ptr<Playlist > > used_playlists;
7036 RegionSelection rs = get_regions_from_selection_and_entered ();
7038 if (!_session || rs.empty()) {
7042 Dialog dialog (_("Close Region Gaps"));
7045 table.set_spacings (12);
7046 table.set_border_width (12);
7047 Label* l = manage (left_aligned_label (_("Crossfade length")));
7048 table.attach (*l, 0, 1, 0, 1);
7050 SpinButton spin_crossfade (1, 0);
7051 spin_crossfade.set_range (0, 15);
7052 spin_crossfade.set_increments (1, 1);
7053 spin_crossfade.set_value (5);
7054 table.attach (spin_crossfade, 1, 2, 0, 1);
7056 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7058 l = manage (left_aligned_label (_("Pull-back length")));
7059 table.attach (*l, 0, 1, 1, 2);
7061 SpinButton spin_pullback (1, 0);
7062 spin_pullback.set_range (0, 100);
7063 spin_pullback.set_increments (1, 1);
7064 spin_pullback.set_value(30);
7065 table.attach (spin_pullback, 1, 2, 1, 2);
7067 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7069 dialog.get_vbox()->pack_start (table);
7070 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7071 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7074 if (dialog.run () == RESPONSE_CANCEL) {
7078 framepos_t crossfade_len = spin_crossfade.get_value();
7079 framepos_t pull_back_frames = spin_pullback.get_value();
7081 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7082 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7084 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7086 begin_reversible_command (_("close region gaps"));
7089 boost::shared_ptr<Region> last_region;
7091 rs.sort_by_position_and_track();
7093 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7095 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7097 if (!pl->frozen()) {
7098 /* we haven't seen this playlist before */
7100 /* remember used playlists so we can thaw them later */
7101 used_playlists.push_back(pl);
7105 framepos_t position = (*r)->region()->position();
7107 if (idx == 0 || position < last_region->position()){
7108 last_region = (*r)->region();
7113 (*r)->region()->trim_front( (position - pull_back_frames));
7114 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7116 last_region = (*r)->region();
7121 while (used_playlists.size() > 0) {
7122 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7124 used_playlists.pop_front();
7127 commit_reversible_command ();
7131 Editor::tab_to_transient (bool forward)
7133 AnalysisFeatureList positions;
7135 RegionSelection rs = get_regions_from_selection_and_entered ();
7141 framepos_t pos = _session->audible_frame ();
7143 if (!selection->tracks.empty()) {
7145 /* don't waste time searching for transients in duplicate playlists.
7148 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7150 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7152 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7155 boost::shared_ptr<Track> tr = rtv->track();
7157 boost::shared_ptr<Playlist> pl = tr->playlist ();
7159 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7162 positions.push_back (result);
7175 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7176 (*r)->region()->get_transients (positions);
7180 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7183 AnalysisFeatureList::iterator x;
7185 for (x = positions.begin(); x != positions.end(); ++x) {
7191 if (x != positions.end ()) {
7192 _session->request_locate (*x);
7196 AnalysisFeatureList::reverse_iterator x;
7198 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7204 if (x != positions.rend ()) {
7205 _session->request_locate (*x);
7211 Editor::playhead_forward_to_grid ()
7217 framepos_t pos = playhead_cursor->current_frame ();
7218 if (pos < max_framepos - 1) {
7220 snap_to_internal (pos, RoundUpAlways, false);
7221 _session->request_locate (pos);
7227 Editor::playhead_backward_to_grid ()
7233 framepos_t pos = playhead_cursor->current_frame ();
7236 snap_to_internal (pos, RoundDownAlways, false);
7237 _session->request_locate (pos);
7242 Editor::set_track_height (Height h)
7244 TrackSelection& ts (selection->tracks);
7246 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7247 (*x)->set_height_enum (h);
7252 Editor::toggle_tracks_active ()
7254 TrackSelection& ts (selection->tracks);
7256 bool target = false;
7262 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7263 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7267 target = !rtv->_route->active();
7270 rtv->_route->set_active (target, this);
7276 Editor::remove_tracks ()
7278 /* this will delete GUI objects that may be the subject of an event
7279 handler in which this method is called. Defer actual deletion to the
7280 next idle callback, when all event handling is finished.
7282 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7286 Editor::idle_remove_tracks ()
7288 Session::StateProtector sp (_session);
7290 return false; /* do not call again */
7294 Editor::_remove_tracks ()
7296 TrackSelection& ts (selection->tracks);
7302 vector<string> choices;
7306 const char* trackstr;
7308 vector<boost::shared_ptr<Route> > routes;
7309 bool special_bus = false;
7311 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7312 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7316 if (rtv->is_track()) {
7321 routes.push_back (rtv->_route);
7323 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7328 if (special_bus && !Config->get_allow_special_bus_removal()) {
7329 MessageDialog msg (_("That would be bad news ...."),
7333 msg.set_secondary_text (string_compose (_(
7334 "Removing the master or monitor bus is such a bad idea\n\
7335 that %1 is not going to allow it.\n\
7337 If you really want to do this sort of thing\n\
7338 edit your ardour.rc file to set the\n\
7339 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7346 if (ntracks + nbusses == 0) {
7350 trackstr = P_("track", "tracks", ntracks);
7351 busstr = P_("bus", "busses", nbusses);
7355 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\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!"),
7358 ntracks, trackstr, nbusses, busstr);
7360 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7361 "(You may also lose the playlists associated with the %2)\n\n"
7362 "This action cannot be undone, and the session file will be overwritten!"),
7365 } else if (nbusses) {
7366 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7367 "This action cannot be undone, and the session file will be overwritten"),
7371 choices.push_back (_("No, do nothing."));
7372 if (ntracks + nbusses > 1) {
7373 choices.push_back (_("Yes, remove them."));
7375 choices.push_back (_("Yes, remove it."));
7380 title = string_compose (_("Remove %1"), trackstr);
7382 title = string_compose (_("Remove %1"), busstr);
7385 Choice prompter (title, prompt, choices);
7387 if (prompter.run () != 1) {
7392 Mixer_UI::instance()->selection().block_routes_changed (true);
7393 selection->block_tracks_changed (true);
7395 DisplaySuspender ds;
7396 boost::shared_ptr<RouteList> rl (new RouteList);
7397 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7400 _session->remove_routes (rl);
7402 /* TrackSelection and RouteList leave scope,
7403 * destructors are called,
7404 * diskstream drops references, save_state is called (again for every track)
7406 selection->block_tracks_changed (false);
7407 Mixer_UI::instance()->selection().block_routes_changed (false);
7408 selection->TracksChanged (); /* EMIT SIGNAL */
7412 Editor::do_insert_time ()
7414 if (selection->tracks.empty()) {
7418 InsertRemoveTimeDialog d (*this);
7419 int response = d.run ();
7421 if (response != RESPONSE_OK) {
7425 if (d.distance() == 0) {
7432 d.intersected_region_action (),
7436 d.move_glued_markers(),
7437 d.move_locked_markers(),
7443 Editor::insert_time (
7444 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7445 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7449 if (Config->get_edit_mode() == Lock) {
7452 bool in_command = false;
7454 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7456 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7460 /* don't operate on any playlist more than once, which could
7461 * happen if "all playlists" is enabled, but there is more
7462 * than 1 track using playlists "from" a given track.
7465 set<boost::shared_ptr<Playlist> > pl;
7467 if (all_playlists) {
7468 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7469 if (rtav && rtav->track ()) {
7470 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7471 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7476 if ((*x)->playlist ()) {
7477 pl.insert ((*x)->playlist ());
7481 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7483 (*i)->clear_changes ();
7484 (*i)->clear_owned_changes ();
7486 if (opt == SplitIntersected) {
7487 /* non musical split */
7488 (*i)->split (pos, 0);
7491 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7494 begin_reversible_command (_("insert time"));
7497 vector<Command*> cmds;
7499 _session->add_commands (cmds);
7501 _session->add_command (new StatefulDiffCommand (*i));
7505 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7508 begin_reversible_command (_("insert time"));
7511 rtav->route ()->shift (pos, frames);
7518 XMLNode& before (_session->locations()->get_state());
7519 Locations::LocationList copy (_session->locations()->list());
7521 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7523 Locations::LocationList::const_iterator tmp;
7525 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7526 bool const was_locked = (*i)->locked ();
7527 if (locked_markers_too) {
7531 if ((*i)->start() >= pos) {
7532 // move end first, in case we're moving by more than the length of the range
7533 if (!(*i)->is_mark()) {
7534 (*i)->set_end ((*i)->end() + frames);
7536 (*i)->set_start ((*i)->start() + frames);
7548 begin_reversible_command (_("insert time"));
7551 XMLNode& after (_session->locations()->get_state());
7552 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7558 begin_reversible_command (_("insert time"));
7561 XMLNode& before (_session->tempo_map().get_state());
7562 _session->tempo_map().insert_time (pos, frames);
7563 XMLNode& after (_session->tempo_map().get_state());
7564 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7568 commit_reversible_command ();
7573 Editor::do_remove_time ()
7575 if (selection->tracks.empty()) {
7579 InsertRemoveTimeDialog d (*this, true);
7581 int response = d.run ();
7583 if (response != RESPONSE_OK) {
7587 framecnt_t distance = d.distance();
7589 if (distance == 0) {
7599 d.move_glued_markers(),
7600 d.move_locked_markers(),
7606 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7607 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7609 if (Config->get_edit_mode() == Lock) {
7610 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7613 bool in_command = false;
7615 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7617 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7621 XMLNode &before = pl->get_state();
7623 std::list<AudioRange> rl;
7624 AudioRange ar(pos, pos+frames, 0);
7627 pl->shift (pos, -frames, true, ignore_music_glue);
7630 begin_reversible_command (_("remove time"));
7633 XMLNode &after = pl->get_state();
7635 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7639 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7642 begin_reversible_command (_("remove time"));
7645 rtav->route ()->shift (pos, -frames);
7649 std::list<Location*> loc_kill_list;
7654 XMLNode& before (_session->locations()->get_state());
7655 Locations::LocationList copy (_session->locations()->list());
7657 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7658 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7660 bool const was_locked = (*i)->locked ();
7661 if (locked_markers_too) {
7665 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7666 if ((*i)->end() >= pos
7667 && (*i)->end() < pos+frames
7668 && (*i)->start() >= pos
7669 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7671 loc_kill_list.push_back(*i);
7672 } else { // only start or end is included, try to do the right thing
7673 // move start before moving end, to avoid trying to move the end to before the start
7674 // if we're removing more time than the length of the range
7675 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7676 // start is within cut
7677 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7679 } else if ((*i)->start() >= pos+frames) {
7680 // start (and thus entire range) lies beyond end of cut
7681 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7684 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7685 // end is inside cut
7686 (*i)->set_end (pos); // bring the end to the cut
7688 } else if ((*i)->end() >= pos+frames) {
7689 // end is beyond end of cut
7690 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7695 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7696 loc_kill_list.push_back(*i);
7698 } else if ((*i)->start() >= pos) {
7699 (*i)->set_start ((*i)->start() -frames);
7709 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7710 _session->locations()->remove( *i );
7715 begin_reversible_command (_("remove time"));
7718 XMLNode& after (_session->locations()->get_state());
7719 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7724 XMLNode& before (_session->tempo_map().get_state());
7726 if (_session->tempo_map().remove_time (pos, frames) ) {
7728 begin_reversible_command (_("remove time"));
7731 XMLNode& after (_session->tempo_map().get_state());
7732 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7737 commit_reversible_command ();
7742 Editor::fit_selection ()
7744 if (!selection->tracks.empty()) {
7745 fit_tracks (selection->tracks);
7749 /* no selected tracks - use tracks with selected regions */
7751 if (!selection->regions.empty()) {
7752 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7753 tvl.push_back (&(*r)->get_time_axis_view ());
7759 } else if (internal_editing()) {
7760 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7763 if (entered_track) {
7764 tvl.push_back (entered_track);
7773 Editor::fit_tracks (TrackViewList & tracks)
7775 if (tracks.empty()) {
7779 uint32_t child_heights = 0;
7780 int visible_tracks = 0;
7782 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7784 if (!(*t)->marked_for_display()) {
7788 child_heights += (*t)->effective_height() - (*t)->current_height();
7792 /* compute the per-track height from:
7794 total canvas visible height -
7795 height that will be taken by visible children of selected
7796 tracks - height of the ruler/hscroll area
7798 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7799 double first_y_pos = DBL_MAX;
7801 if (h < TimeAxisView::preset_height (HeightSmall)) {
7802 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7803 /* too small to be displayed */
7807 undo_visual_stack.push_back (current_visual_state (true));
7808 PBD::Unwinder<bool> nsv (no_save_visual, true);
7810 /* build a list of all tracks, including children */
7813 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7815 TimeAxisView::Children c = (*i)->get_child_list ();
7816 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7817 all.push_back (j->get());
7822 // find selection range.
7823 // if someone knows how to user TrackViewList::iterator for this
7825 int selected_top = -1;
7826 int selected_bottom = -1;
7828 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7829 if ((*t)->marked_for_display ()) {
7830 if (tracks.contains(*t)) {
7831 if (selected_top == -1) {
7834 selected_bottom = i;
7840 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7841 if ((*t)->marked_for_display ()) {
7842 if (tracks.contains(*t)) {
7843 (*t)->set_height (h);
7844 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7846 if (i > selected_top && i < selected_bottom) {
7847 hide_track_in_display (*t);
7854 set the controls_layout height now, because waiting for its size
7855 request signal handler will cause the vertical adjustment setting to fail
7858 controls_layout.property_height () = _full_canvas_height;
7859 vertical_adjustment.set_value (first_y_pos);
7861 redo_visual_stack.push_back (current_visual_state (true));
7863 visible_tracks_selector.set_text (_("Sel"));
7867 Editor::save_visual_state (uint32_t n)
7869 while (visual_states.size() <= n) {
7870 visual_states.push_back (0);
7873 if (visual_states[n] != 0) {
7874 delete visual_states[n];
7877 visual_states[n] = current_visual_state (true);
7882 Editor::goto_visual_state (uint32_t n)
7884 if (visual_states.size() <= n) {
7888 if (visual_states[n] == 0) {
7892 use_visual_state (*visual_states[n]);
7896 Editor::start_visual_state_op (uint32_t n)
7898 save_visual_state (n);
7900 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7902 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7903 pup->set_text (buf);
7908 Editor::cancel_visual_state_op (uint32_t n)
7910 goto_visual_state (n);
7914 Editor::toggle_region_mute ()
7916 if (_ignore_region_action) {
7920 RegionSelection rs = get_regions_from_selection_and_entered ();
7926 if (rs.size() > 1) {
7927 begin_reversible_command (_("mute regions"));
7929 begin_reversible_command (_("mute region"));
7932 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7934 (*i)->region()->playlist()->clear_changes ();
7935 (*i)->region()->set_muted (!(*i)->region()->muted ());
7936 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7940 commit_reversible_command ();
7944 Editor::combine_regions ()
7946 /* foreach track with selected regions, take all selected regions
7947 and join them into a new region containing the subregions (as a
7951 typedef set<RouteTimeAxisView*> RTVS;
7954 if (selection->regions.empty()) {
7958 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7959 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7962 tracks.insert (rtv);
7966 begin_reversible_command (_("combine regions"));
7968 vector<RegionView*> new_selection;
7970 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7973 if ((rv = (*i)->combine_regions ()) != 0) {
7974 new_selection.push_back (rv);
7978 selection->clear_regions ();
7979 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7980 selection->add (*i);
7983 commit_reversible_command ();
7987 Editor::uncombine_regions ()
7989 typedef set<RouteTimeAxisView*> RTVS;
7992 if (selection->regions.empty()) {
7996 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7997 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8000 tracks.insert (rtv);
8004 begin_reversible_command (_("uncombine regions"));
8006 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8007 (*i)->uncombine_regions ();
8010 commit_reversible_command ();
8014 Editor::toggle_midi_input_active (bool flip_others)
8017 boost::shared_ptr<RouteList> rl (new RouteList);
8019 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8020 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8026 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8029 rl->push_back (rtav->route());
8030 onoff = !mt->input_active();
8034 _session->set_exclusive_input_active (rl, onoff, flip_others);
8037 static bool ok_fine (GdkEventAny*) { return true; }
8043 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8045 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8046 lock_dialog->get_vbox()->pack_start (*padlock);
8047 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8049 ArdourButton* b = manage (new ArdourButton);
8050 b->set_name ("lock button");
8051 b->set_text (_("Click to unlock"));
8052 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8053 lock_dialog->get_vbox()->pack_start (*b);
8055 lock_dialog->get_vbox()->show_all ();
8056 lock_dialog->set_size_request (200, 200);
8059 delete _main_menu_disabler;
8060 _main_menu_disabler = new MainMenuDisabler;
8062 lock_dialog->present ();
8064 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8070 lock_dialog->hide ();
8072 delete _main_menu_disabler;
8073 _main_menu_disabler = 0;
8075 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8076 start_lock_event_timing ();
8081 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8083 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8087 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8089 Timers::TimerSuspender t;
8090 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8091 Gtkmm2ext::UI::instance()->flush_pending (1);
8095 Editor::bring_all_sources_into_session ()
8102 ArdourDialog w (_("Moving embedded files into session folder"));
8103 w.get_vbox()->pack_start (msg);
8106 /* flush all pending GUI events because we're about to start copying
8110 Timers::TimerSuspender t;
8111 Gtkmm2ext::UI::instance()->flush_pending (3);
8115 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));