2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_remove_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
100 #include "transform_dialog.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
112 /***********************************************************************
114 ***********************************************************************/
117 Editor::undo (uint32_t n)
119 if (_drags->active ()) {
125 if (_session->undo_depth() == 0) {
126 undo_action->set_sensitive(false);
128 redo_action->set_sensitive(true);
129 begin_selection_op_history ();
134 Editor::redo (uint32_t n)
136 if (_drags->active ()) {
142 if (_session->redo_depth() == 0) {
143 redo_action->set_sensitive(false);
145 undo_action->set_sensitive(true);
146 begin_selection_op_history ();
151 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
155 RegionSelection pre_selected_regions = selection->regions;
156 bool working_on_selection = !pre_selected_regions.empty();
158 list<boost::shared_ptr<Playlist> > used_playlists;
159 list<RouteTimeAxisView*> used_trackviews;
161 if (regions.empty()) {
165 begin_reversible_command (_("split"));
167 // if splitting a single region, and snap-to is using
168 // region boundaries, don't pay attention to them
170 if (regions.size() == 1) {
171 switch (_snap_type) {
172 case SnapToRegionStart:
173 case SnapToRegionSync:
174 case SnapToRegionEnd:
183 EditorFreeze(); /* Emit Signal */
186 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
188 RegionSelection::iterator tmp;
190 /* XXX this test needs to be more complicated, to make sure we really
191 have something to split.
194 if (!(*a)->region()->covers (where)) {
202 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
210 /* we haven't seen this playlist before */
212 /* remember used playlists so we can thaw them later */
213 used_playlists.push_back(pl);
215 TimeAxisView& tv = (*a)->get_time_axis_view();
216 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
218 used_trackviews.push_back (rtv);
225 pl->clear_changes ();
226 pl->split_region ((*a)->region(), where);
227 _session->add_command (new StatefulDiffCommand (pl));
233 latest_regionviews.clear ();
235 vector<sigc::connection> region_added_connections;
237 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
238 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
241 while (used_playlists.size() > 0) {
242 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
244 used_playlists.pop_front();
247 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
252 EditorThaw(); /* Emit Signal */
255 if (working_on_selection) {
256 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
258 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
259 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
260 /* There are three classes of regions that we might want selected after
261 splitting selected regions:
262 - regions selected before the split operation, and unaffected by it
263 - newly-created regions before the split
264 - newly-created regions after the split
267 if (rsas & Existing) {
268 // region selections that existed before the split.
269 selection->add ( pre_selected_regions );
272 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
273 if ((*ri)->region()->position() < where) {
274 // new regions created before the split
275 if (rsas & NewlyCreatedLeft) {
276 selection->add (*ri);
279 // new regions created after the split
280 if (rsas & NewlyCreatedRight) {
281 selection->add (*ri);
285 _ignore_follow_edits = false;
287 _ignore_follow_edits = true;
288 if( working_on_selection ) {
289 selection->add (latest_regionviews); //these are the new regions created after the split
291 _ignore_follow_edits = false;
294 commit_reversible_command ();
297 /** Move one extreme of the current range selection. If more than one range is selected,
298 * the start of the earliest range or the end of the latest range is moved.
300 * @param move_end true to move the end of the current range selection, false to move
302 * @param next true to move the extreme to the next region boundary, false to move to
306 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
308 if (selection->time.start() == selection->time.end_frame()) {
312 framepos_t start = selection->time.start ();
313 framepos_t end = selection->time.end_frame ();
315 /* the position of the thing we may move */
316 framepos_t pos = move_end ? end : start;
317 int dir = next ? 1 : -1;
319 /* so we don't find the current region again */
320 if (dir > 0 || pos > 0) {
324 framepos_t const target = get_region_boundary (pos, dir, true, false);
339 begin_reversible_command (_("alter selection"));
340 selection->set_preserving_all_ranges (start, end);
341 commit_reversible_command ();
345 Editor::nudge_forward_release (GdkEventButton* ev)
347 if (ev->state & Keyboard::PrimaryModifier) {
348 nudge_forward (false, true);
350 nudge_forward (false, false);
356 Editor::nudge_backward_release (GdkEventButton* ev)
358 if (ev->state & Keyboard::PrimaryModifier) {
359 nudge_backward (false, true);
361 nudge_backward (false, false);
368 Editor::nudge_forward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions forward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
393 r->set_position (r->position() + distance);
394 _session->add_command (new StatefulDiffCommand (r));
397 commit_reversible_command ();
400 } else if (!force_playhead && !selection->markers.empty()) {
404 begin_reversible_command (_("nudge location forward"));
406 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
408 Location* loc = find_location_from_marker ((*i), is_start);
412 XMLNode& before (loc->get_state());
415 distance = get_nudge_distance (loc->start(), next_distance);
417 distance = next_distance;
419 if (max_framepos - distance > loc->start() + loc->length()) {
420 loc->set_start (loc->start() + distance);
422 loc->set_start (max_framepos - loc->length());
425 distance = get_nudge_distance (loc->end(), next_distance);
427 distance = next_distance;
429 if (max_framepos - distance > loc->end()) {
430 loc->set_end (loc->end() + distance);
432 loc->set_end (max_framepos);
435 XMLNode& after (loc->get_state());
436 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
440 commit_reversible_command ();
443 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
444 _session->request_locate (playhead_cursor->current_frame () + distance);
449 Editor::nudge_backward (bool next, bool force_playhead)
452 framepos_t next_distance;
458 RegionSelection rs = get_regions_from_selection_and_entered ();
460 if (!force_playhead && !rs.empty()) {
462 begin_reversible_command (_("nudge regions backward"));
464 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
465 boost::shared_ptr<Region> r ((*i)->region());
467 distance = get_nudge_distance (r->position(), next_distance);
470 distance = next_distance;
475 if (r->position() > distance) {
476 r->set_position (r->position() - distance);
480 _session->add_command (new StatefulDiffCommand (r));
483 commit_reversible_command ();
485 } else if (!force_playhead && !selection->markers.empty()) {
489 begin_reversible_command (_("nudge location forward"));
491 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
493 Location* loc = find_location_from_marker ((*i), is_start);
497 XMLNode& before (loc->get_state());
500 distance = get_nudge_distance (loc->start(), next_distance);
502 distance = next_distance;
504 if (distance < loc->start()) {
505 loc->set_start (loc->start() - distance);
510 distance = get_nudge_distance (loc->end(), next_distance);
513 distance = next_distance;
516 if (distance < loc->end() - loc->length()) {
517 loc->set_end (loc->end() - distance);
519 loc->set_end (loc->length());
523 XMLNode& after (loc->get_state());
524 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
528 commit_reversible_command ();
532 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
534 if (playhead_cursor->current_frame () > distance) {
535 _session->request_locate (playhead_cursor->current_frame () - distance);
537 _session->goto_start();
543 Editor::nudge_forward_capture_offset ()
545 RegionSelection rs = get_regions_from_selection_and_entered ();
547 if (!_session || rs.empty()) {
551 begin_reversible_command (_("nudge forward"));
553 framepos_t const distance = _session->worst_output_latency();
555 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
556 boost::shared_ptr<Region> r ((*i)->region());
559 r->set_position (r->position() + distance);
560 _session->add_command(new StatefulDiffCommand (r));
563 commit_reversible_command ();
567 Editor::nudge_backward_capture_offset ()
569 RegionSelection rs = get_regions_from_selection_and_entered ();
571 if (!_session || rs.empty()) {
575 begin_reversible_command (_("nudge backward"));
577 framepos_t const distance = _session->worst_output_latency();
579 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
580 boost::shared_ptr<Region> r ((*i)->region());
584 if (r->position() > distance) {
585 r->set_position (r->position() - distance);
589 _session->add_command(new StatefulDiffCommand (r));
592 commit_reversible_command ();
595 struct RegionSelectionPositionSorter {
596 bool operator() (RegionView* a, RegionView* b) {
597 return a->region()->position() < b->region()->position();
602 Editor::sequence_regions ()
605 framepos_t r_end_prev;
613 RegionSelection rs = get_regions_from_selection_and_entered ();
614 rs.sort(RegionSelectionPositionSorter());
618 begin_reversible_command (_("sequence regions"));
619 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
620 boost::shared_ptr<Region> r ((*i)->region());
628 if(r->position_locked())
635 r->set_position(r_end_prev);
638 _session->add_command (new StatefulDiffCommand (r));
640 r_end=r->position() + r->length();
644 commit_reversible_command ();
652 Editor::move_to_start ()
654 _session->goto_start ();
658 Editor::move_to_end ()
661 _session->request_locate (_session->current_end_frame());
665 Editor::build_region_boundary_cache ()
668 vector<RegionPoint> interesting_points;
669 boost::shared_ptr<Region> r;
670 TrackViewList tracks;
673 region_boundary_cache.clear ();
679 switch (_snap_type) {
680 case SnapToRegionStart:
681 interesting_points.push_back (Start);
683 case SnapToRegionEnd:
684 interesting_points.push_back (End);
686 case SnapToRegionSync:
687 interesting_points.push_back (SyncPoint);
689 case SnapToRegionBoundary:
690 interesting_points.push_back (Start);
691 interesting_points.push_back (End);
694 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
695 abort(); /*NOTREACHED*/
699 TimeAxisView *ontrack = 0;
702 if (!selection->tracks.empty()) {
703 tlist = selection->tracks.filter_to_unique_playlists ();
705 tlist = track_views.filter_to_unique_playlists ();
708 while (pos < _session->current_end_frame() && !at_end) {
711 framepos_t lpos = max_framepos;
713 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
715 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
716 if (*p == interesting_points.back()) {
719 /* move to next point type */
725 rpos = r->first_frame();
729 rpos = r->last_frame();
733 rpos = r->sync_position ();
741 RouteTimeAxisView *rtav;
743 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
744 if (rtav->track() != 0) {
745 speed = rtav->track()->speed();
749 rpos = track_frame_to_session_frame (rpos, speed);
755 /* prevent duplicates, but we don't use set<> because we want to be able
759 vector<framepos_t>::iterator ri;
761 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
767 if (ri == region_boundary_cache.end()) {
768 region_boundary_cache.push_back (rpos);
775 /* finally sort to be sure that the order is correct */
777 sort (region_boundary_cache.begin(), region_boundary_cache.end());
780 boost::shared_ptr<Region>
781 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
783 TrackViewList::iterator i;
784 framepos_t closest = max_framepos;
785 boost::shared_ptr<Region> ret;
789 framepos_t track_frame;
790 RouteTimeAxisView *rtav;
792 for (i = tracks.begin(); i != tracks.end(); ++i) {
795 boost::shared_ptr<Region> r;
798 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
799 if (rtav->track()!=0)
800 track_speed = rtav->track()->speed();
803 track_frame = session_frame_to_track_frame(frame, track_speed);
805 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
811 rpos = r->first_frame ();
815 rpos = r->last_frame ();
819 rpos = r->sync_position ();
823 // rpos is a "track frame", converting it to "_session frame"
824 rpos = track_frame_to_session_frame(rpos, track_speed);
827 distance = rpos - frame;
829 distance = frame - rpos;
832 if (distance < closest) {
844 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
846 framecnt_t distance = max_framepos;
847 framepos_t current_nearest = -1;
849 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
850 framepos_t contender;
853 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
859 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
863 d = ::llabs (pos - contender);
866 current_nearest = contender;
871 return current_nearest;
875 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
880 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
882 if (!selection->tracks.empty()) {
884 target = find_next_region_boundary (pos, dir, selection->tracks);
888 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
889 get_onscreen_tracks (tvl);
890 target = find_next_region_boundary (pos, dir, tvl);
892 target = find_next_region_boundary (pos, dir, track_views);
898 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
899 get_onscreen_tracks (tvl);
900 target = find_next_region_boundary (pos, dir, tvl);
902 target = find_next_region_boundary (pos, dir, track_views);
910 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
912 framepos_t pos = playhead_cursor->current_frame ();
919 // so we don't find the current region again..
920 if (dir > 0 || pos > 0) {
924 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
928 _session->request_locate (target);
932 Editor::cursor_to_next_region_boundary (bool with_selection)
934 cursor_to_region_boundary (with_selection, 1);
938 Editor::cursor_to_previous_region_boundary (bool with_selection)
940 cursor_to_region_boundary (with_selection, -1);
944 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
946 boost::shared_ptr<Region> r;
947 framepos_t pos = cursor->current_frame ();
953 TimeAxisView *ontrack = 0;
955 // so we don't find the current region again..
959 if (!selection->tracks.empty()) {
961 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
963 } else if (clicked_axisview) {
966 t.push_back (clicked_axisview);
968 r = find_next_region (pos, point, dir, t, &ontrack);
972 r = find_next_region (pos, point, dir, track_views, &ontrack);
981 pos = r->first_frame ();
985 pos = r->last_frame ();
989 pos = r->sync_position ();
994 RouteTimeAxisView *rtav;
996 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
997 if (rtav->track() != 0) {
998 speed = rtav->track()->speed();
1002 pos = track_frame_to_session_frame(pos, speed);
1004 if (cursor == playhead_cursor) {
1005 _session->request_locate (pos);
1007 cursor->set_position (pos);
1012 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1014 cursor_to_region_point (cursor, point, 1);
1018 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1020 cursor_to_region_point (cursor, point, -1);
1024 Editor::cursor_to_selection_start (EditorCursor *cursor)
1028 switch (mouse_mode) {
1030 if (!selection->regions.empty()) {
1031 pos = selection->regions.start();
1036 if (!selection->time.empty()) {
1037 pos = selection->time.start ();
1045 if (cursor == playhead_cursor) {
1046 _session->request_locate (pos);
1048 cursor->set_position (pos);
1053 Editor::cursor_to_selection_end (EditorCursor *cursor)
1057 switch (mouse_mode) {
1059 if (!selection->regions.empty()) {
1060 pos = selection->regions.end_frame();
1065 if (!selection->time.empty()) {
1066 pos = selection->time.end_frame ();
1074 if (cursor == playhead_cursor) {
1075 _session->request_locate (pos);
1077 cursor->set_position (pos);
1082 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1092 if (selection->markers.empty()) {
1096 if (!mouse_frame (mouse, ignored)) {
1100 add_location_mark (mouse);
1103 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1107 framepos_t pos = loc->start();
1109 // so we don't find the current region again..
1110 if (dir > 0 || pos > 0) {
1114 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1118 loc->move_to (target);
1122 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1124 selected_marker_to_region_boundary (with_selection, 1);
1128 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1130 selected_marker_to_region_boundary (with_selection, -1);
1134 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1136 boost::shared_ptr<Region> r;
1141 if (!_session || selection->markers.empty()) {
1145 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1149 TimeAxisView *ontrack = 0;
1153 // so we don't find the current region again..
1157 if (!selection->tracks.empty()) {
1159 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1163 r = find_next_region (pos, point, dir, track_views, &ontrack);
1172 pos = r->first_frame ();
1176 pos = r->last_frame ();
1180 pos = r->adjust_to_sync (r->first_frame());
1185 RouteTimeAxisView *rtav;
1187 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1188 if (rtav->track() != 0) {
1189 speed = rtav->track()->speed();
1193 pos = track_frame_to_session_frame(pos, speed);
1199 Editor::selected_marker_to_next_region_point (RegionPoint point)
1201 selected_marker_to_region_point (point, 1);
1205 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1207 selected_marker_to_region_point (point, -1);
1211 Editor::selected_marker_to_selection_start ()
1217 if (!_session || selection->markers.empty()) {
1221 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1225 switch (mouse_mode) {
1227 if (!selection->regions.empty()) {
1228 pos = selection->regions.start();
1233 if (!selection->time.empty()) {
1234 pos = selection->time.start ();
1246 Editor::selected_marker_to_selection_end ()
1252 if (!_session || selection->markers.empty()) {
1256 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1260 switch (mouse_mode) {
1262 if (!selection->regions.empty()) {
1263 pos = selection->regions.end_frame();
1268 if (!selection->time.empty()) {
1269 pos = selection->time.end_frame ();
1281 Editor::scroll_playhead (bool forward)
1283 framepos_t pos = playhead_cursor->current_frame ();
1284 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1287 if (pos == max_framepos) {
1291 if (pos < max_framepos - delta) {
1310 _session->request_locate (pos);
1314 Editor::cursor_align (bool playhead_to_edit)
1320 if (playhead_to_edit) {
1322 if (selection->markers.empty()) {
1326 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1329 /* move selected markers to playhead */
1331 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1334 Location* loc = find_location_from_marker (*i, ignored);
1336 if (loc->is_mark()) {
1337 loc->set_start (playhead_cursor->current_frame ());
1339 loc->set (playhead_cursor->current_frame (),
1340 playhead_cursor->current_frame () + loc->length());
1347 Editor::scroll_backward (float pages)
1349 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1350 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1353 if (leftmost_frame < cnt) {
1356 frame = leftmost_frame - cnt;
1359 reset_x_origin (frame);
1363 Editor::scroll_forward (float pages)
1365 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1366 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1369 if (max_framepos - cnt < leftmost_frame) {
1370 frame = max_framepos - cnt;
1372 frame = leftmost_frame + cnt;
1375 reset_x_origin (frame);
1379 Editor::scroll_tracks_down ()
1381 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1382 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1383 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1386 vertical_adjustment.set_value (vert_value);
1390 Editor::scroll_tracks_up ()
1392 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1396 Editor::scroll_tracks_down_line ()
1398 double vert_value = vertical_adjustment.get_value() + 60;
1400 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1401 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1404 vertical_adjustment.set_value (vert_value);
1408 Editor::scroll_tracks_up_line ()
1410 reset_y_origin (vertical_adjustment.get_value() - 60);
1414 Editor::scroll_down_one_track (bool skip_child_views)
1416 TrackViewList::reverse_iterator next = track_views.rend();
1417 const double top_of_trackviews = vertical_adjustment.get_value();
1419 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1420 if ((*t)->hidden()) {
1424 /* If this is the upper-most visible trackview, we want to display
1425 * the one above it (next)
1427 * Note that covers_y_position() is recursive and includes child views
1429 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1432 if (skip_child_views) {
1435 /* automation lane (one level, non-recursive)
1437 * - if no automation lane exists -> move to next tack
1438 * - if the first (here: bottom-most) matches -> move to next tack
1439 * - if no y-axis match is found -> the current track is at the top
1440 * -> move to last (here: top-most) automation lane
1442 TimeAxisView::Children kids = (*t)->get_child_list();
1443 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1445 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1446 if ((*ci)->hidden()) {
1450 std::pair<TimeAxisView*,double> dev;
1451 dev = (*ci)->covers_y_position (top_of_trackviews);
1453 /* some automation lane is currently at the top */
1454 if (ci == kids.rbegin()) {
1455 /* first (bottom-most) autmation lane is at the top.
1456 * -> move to next track
1465 if (nkid != kids.rend()) {
1466 ensure_time_axis_view_is_visible (**nkid, true);
1474 /* move to the track below the first one that covers the */
1476 if (next != track_views.rend()) {
1477 ensure_time_axis_view_is_visible (**next, true);
1485 Editor::scroll_up_one_track (bool skip_child_views)
1487 TrackViewList::iterator prev = track_views.end();
1488 double top_of_trackviews = vertical_adjustment.get_value ();
1490 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1492 if ((*t)->hidden()) {
1496 /* find the trackview at the top of the trackview group
1498 * Note that covers_y_position() is recursive and includes child views
1500 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1503 if (skip_child_views) {
1506 /* automation lane (one level, non-recursive)
1508 * - if no automation lane exists -> move to prev tack
1509 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1510 * (actually last automation lane of previous track, see below)
1511 * - if first (top-most) lane is at the top -> move to this track
1512 * - else move up one lane
1514 TimeAxisView::Children kids = (*t)->get_child_list();
1515 TimeAxisView::Children::iterator pkid = kids.end();
1517 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1518 if ((*ci)->hidden()) {
1522 std::pair<TimeAxisView*,double> dev;
1523 dev = (*ci)->covers_y_position (top_of_trackviews);
1525 /* some automation lane is currently at the top */
1526 if (ci == kids.begin()) {
1527 /* first (top-most) autmation lane is at the top.
1528 * jump directly to this track's top
1530 ensure_time_axis_view_is_visible (**t, true);
1533 else if (pkid != kids.end()) {
1534 /* some other automation lane is at the top.
1535 * move up to prev automation lane.
1537 ensure_time_axis_view_is_visible (**pkid, true);
1540 assert(0); // not reached
1551 if (prev != track_views.end()) {
1552 // move to bottom-most automation-lane of the previous track
1553 TimeAxisView::Children kids = (*prev)->get_child_list();
1554 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1555 if (!skip_child_views) {
1556 // find the last visible lane
1557 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1558 if (!(*ci)->hidden()) {
1564 if (pkid != kids.rend()) {
1565 ensure_time_axis_view_is_visible (**pkid, true);
1567 ensure_time_axis_view_is_visible (**prev, true);
1578 Editor::tav_zoom_step (bool coarser)
1580 DisplaySuspender ds;
1584 if (selection->tracks.empty()) {
1587 ts = &selection->tracks;
1590 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1591 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1592 tv->step_height (coarser);
1597 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1599 DisplaySuspender ds;
1603 if (selection->tracks.empty() || force_all) {
1606 ts = &selection->tracks;
1609 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1610 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1611 uint32_t h = tv->current_height ();
1616 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1621 tv->set_height (h + 5);
1628 Editor::temporal_zoom_step (bool coarser)
1630 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1632 framecnt_t nspp = samples_per_pixel;
1640 temporal_zoom (nspp);
1644 Editor::temporal_zoom (framecnt_t fpp)
1650 framepos_t current_page = current_page_samples();
1651 framepos_t current_leftmost = leftmost_frame;
1652 framepos_t current_rightmost;
1653 framepos_t current_center;
1654 framepos_t new_page_size;
1655 framepos_t half_page_size;
1656 framepos_t leftmost_after_zoom = 0;
1658 bool in_track_canvas;
1662 if (fpp == samples_per_pixel) {
1666 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1667 // segfaults for lack of memory. If somebody decides this is not high enough I
1668 // believe it can be raisen to higher values but some limit must be in place.
1670 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1671 // all of which is used for the editor track displays. The whole day
1672 // would be 4147200000 samples, so 2592000 samples per pixel.
1674 nfpp = min (fpp, (framecnt_t) 2592000);
1675 nfpp = max ((framecnt_t) 1, nfpp);
1677 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1678 half_page_size = new_page_size / 2;
1680 switch (zoom_focus) {
1682 leftmost_after_zoom = current_leftmost;
1685 case ZoomFocusRight:
1686 current_rightmost = leftmost_frame + current_page;
1687 if (current_rightmost < new_page_size) {
1688 leftmost_after_zoom = 0;
1690 leftmost_after_zoom = current_rightmost - new_page_size;
1694 case ZoomFocusCenter:
1695 current_center = current_leftmost + (current_page/2);
1696 if (current_center < half_page_size) {
1697 leftmost_after_zoom = 0;
1699 leftmost_after_zoom = current_center - half_page_size;
1703 case ZoomFocusPlayhead:
1704 /* centre playhead */
1705 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1708 leftmost_after_zoom = 0;
1709 } else if (l > max_framepos) {
1710 leftmost_after_zoom = max_framepos - new_page_size;
1712 leftmost_after_zoom = (framepos_t) l;
1716 case ZoomFocusMouse:
1717 /* try to keep the mouse over the same point in the display */
1719 if (!mouse_frame (where, in_track_canvas)) {
1720 /* use playhead instead */
1721 where = playhead_cursor->current_frame ();
1723 if (where < half_page_size) {
1724 leftmost_after_zoom = 0;
1726 leftmost_after_zoom = where - half_page_size;
1731 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1734 leftmost_after_zoom = 0;
1735 } else if (l > max_framepos) {
1736 leftmost_after_zoom = max_framepos - new_page_size;
1738 leftmost_after_zoom = (framepos_t) l;
1745 /* try to keep the edit point in the same place */
1746 where = get_preferred_edit_position ();
1750 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1753 leftmost_after_zoom = 0;
1754 } else if (l > max_framepos) {
1755 leftmost_after_zoom = max_framepos - new_page_size;
1757 leftmost_after_zoom = (framepos_t) l;
1761 /* edit point not defined */
1768 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1770 reposition_and_zoom (leftmost_after_zoom, nfpp);
1774 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1776 /* this func helps make sure we leave a little space
1777 at each end of the editor so that the zoom doesn't fit the region
1778 precisely to the screen.
1781 GdkScreen* screen = gdk_screen_get_default ();
1782 const gint pixwidth = gdk_screen_get_width (screen);
1783 const gint mmwidth = gdk_screen_get_width_mm (screen);
1784 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1785 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1787 const framepos_t range = end - start;
1788 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1789 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1791 if (start > extra_samples) {
1792 start -= extra_samples;
1797 if (max_framepos - extra_samples > end) {
1798 end += extra_samples;
1805 Editor::temporal_zoom_region (bool both_axes)
1807 framepos_t start = max_framepos;
1809 set<TimeAxisView*> tracks;
1811 if ( !get_selection_extents(start, end) )
1814 calc_extra_zoom_edges (start, end);
1816 /* if we're zooming on both axes we need to save track heights etc.
1819 undo_visual_stack.push_back (current_visual_state (both_axes));
1821 PBD::Unwinder<bool> nsv (no_save_visual, true);
1823 temporal_zoom_by_frame (start, end);
1826 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1828 /* set visible track heights appropriately */
1830 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1831 (*t)->set_height (per_track_height);
1834 /* hide irrelevant tracks */
1836 DisplaySuspender ds;
1838 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1839 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1840 hide_track_in_display (*i);
1844 vertical_adjustment.set_value (0.0);
1847 redo_visual_stack.push_back (current_visual_state (both_axes));
1852 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1854 start = max_framepos;
1858 //ToDo: if notes are selected, set extents to that selection
1860 //ToDo: if control points are selected, set extents to that selection
1862 if ( !selection->regions.empty() ) {
1863 RegionSelection rs = get_regions_from_selection_and_entered ();
1865 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1867 if ((*i)->region()->position() < start) {
1868 start = (*i)->region()->position();
1871 if ((*i)->region()->last_frame() + 1 > end) {
1872 end = (*i)->region()->last_frame() + 1;
1876 } else if (!selection->time.empty()) {
1877 start = selection->time.start();
1878 end = selection->time.end_frame();
1880 ret = false; //no selection found
1883 if ((start == 0 && end == 0) || end < start) {
1892 Editor::temporal_zoom_selection (bool both_axes)
1894 if (!selection) return;
1896 //ToDo: if notes are selected, zoom to that
1898 //ToDo: if control points are selected, zoom to that
1900 //if region(s) are selected, zoom to that
1901 if ( !selection->regions.empty() )
1902 temporal_zoom_region (both_axes);
1904 //if a range is selected, zoom to that
1905 if (!selection->time.empty()) {
1907 framepos_t start, end;
1908 if (get_selection_extents (start, end)) {
1909 calc_extra_zoom_edges(start, end);
1910 temporal_zoom_by_frame (start, end);
1920 Editor::temporal_zoom_session ()
1922 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1925 framecnt_t start = _session->current_start_frame();
1926 framecnt_t end = _session->current_end_frame();
1928 if (_session->actively_recording () ) {
1929 framepos_t cur = playhead_cursor->current_frame ();
1931 /* recording beyond the end marker; zoom out
1932 * by 5 seconds more so that if 'follow
1933 * playhead' is active we don't immediately
1936 end = cur + _session->frame_rate() * 5;
1940 if ((start == 0 && end == 0) || end < start) {
1944 calc_extra_zoom_edges(start, end);
1946 temporal_zoom_by_frame (start, end);
1951 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1953 if (!_session) return;
1955 if ((start == 0 && end == 0) || end < start) {
1959 framepos_t range = end - start;
1961 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1963 framepos_t new_page = range;
1964 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1965 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1967 if (new_leftmost > middle) {
1971 if (new_leftmost < 0) {
1975 reposition_and_zoom (new_leftmost, new_fpp);
1979 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1985 framecnt_t range_before = frame - leftmost_frame;
1989 if (samples_per_pixel <= 1) {
1992 new_spp = samples_per_pixel + (samples_per_pixel/2);
1994 range_before += range_before/2;
1996 if (samples_per_pixel >= 1) {
1997 new_spp = samples_per_pixel - (samples_per_pixel/2);
1999 /* could bail out here since we cannot zoom any finer,
2000 but leave that to the equality test below
2002 new_spp = samples_per_pixel;
2005 range_before -= range_before/2;
2008 if (new_spp == samples_per_pixel) {
2012 /* zoom focus is automatically taken as @param frame when this
2016 framepos_t new_leftmost = frame - (framepos_t)range_before;
2018 if (new_leftmost > frame) {
2022 if (new_leftmost < 0) {
2026 reposition_and_zoom (new_leftmost, new_spp);
2031 Editor::choose_new_marker_name(string &name) {
2033 if (!ARDOUR_UI::config()->get_name_new_markers()) {
2034 /* don't prompt user for a new name */
2038 ArdourPrompter dialog (true);
2040 dialog.set_prompt (_("New Name:"));
2042 dialog.set_title (_("New Location Marker"));
2044 dialog.set_name ("MarkNameWindow");
2045 dialog.set_size_request (250, -1);
2046 dialog.set_position (Gtk::WIN_POS_MOUSE);
2048 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2049 dialog.set_initial_text (name);
2053 switch (dialog.run ()) {
2054 case RESPONSE_ACCEPT:
2060 dialog.get_result(name);
2067 Editor::add_location_from_selection ()
2071 if (selection->time.empty()) {
2075 if (_session == 0 || clicked_axisview == 0) {
2079 framepos_t start = selection->time[clicked_selection].start;
2080 framepos_t end = selection->time[clicked_selection].end;
2082 _session->locations()->next_available_name(rangename,"selection");
2083 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2085 begin_reversible_command (_("add marker"));
2087 XMLNode &before = _session->locations()->get_state();
2088 _session->locations()->add (location, true);
2089 XMLNode &after = _session->locations()->get_state();
2090 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2092 commit_reversible_command ();
2096 Editor::add_location_mark (framepos_t where)
2100 select_new_marker = true;
2102 _session->locations()->next_available_name(markername,"mark");
2103 if (!choose_new_marker_name(markername)) {
2106 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2107 begin_reversible_command (_("add marker"));
2109 XMLNode &before = _session->locations()->get_state();
2110 _session->locations()->add (location, true);
2111 XMLNode &after = _session->locations()->get_state();
2112 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2114 commit_reversible_command ();
2118 Editor::set_session_start_from_playhead ()
2124 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2125 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2127 XMLNode &before = loc->get_state();
2129 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2131 XMLNode &after = loc->get_state();
2133 begin_reversible_command (_("Set session start"));
2135 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2137 commit_reversible_command ();
2142 Editor::set_session_end_from_playhead ()
2148 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2149 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2151 XMLNode &before = loc->get_state();
2153 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2155 XMLNode &after = loc->get_state();
2157 begin_reversible_command (_("Set session start"));
2159 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2161 commit_reversible_command ();
2166 Editor::add_location_from_playhead_cursor ()
2168 add_location_mark (_session->audible_frame());
2172 Editor::remove_location_at_playhead_cursor ()
2177 begin_reversible_command (_("remove marker"));
2179 XMLNode &before = _session->locations()->get_state();
2180 bool removed = false;
2182 //find location(s) at this time
2183 Locations::LocationList locs;
2184 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2185 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2186 if ((*i)->is_mark()) {
2187 _session->locations()->remove (*i);
2194 XMLNode &after = _session->locations()->get_state();
2195 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2197 commit_reversible_command ();
2202 /** Add a range marker around each selected region */
2204 Editor::add_locations_from_region ()
2206 RegionSelection rs = get_regions_from_selection_and_entered ();
2212 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2214 XMLNode &before = _session->locations()->get_state();
2216 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2218 boost::shared_ptr<Region> region = (*i)->region ();
2220 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2222 _session->locations()->add (location, true);
2225 XMLNode &after = _session->locations()->get_state();
2226 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2228 commit_reversible_command ();
2231 /** Add a single range marker around all selected regions */
2233 Editor::add_location_from_region ()
2235 RegionSelection rs = get_regions_from_selection_and_entered ();
2241 begin_reversible_command (_("add marker"));
2243 XMLNode &before = _session->locations()->get_state();
2247 if (rs.size() > 1) {
2248 _session->locations()->next_available_name(markername, "regions");
2250 RegionView* rv = *(rs.begin());
2251 boost::shared_ptr<Region> region = rv->region();
2252 markername = region->name();
2255 if (!choose_new_marker_name(markername)) {
2259 // single range spanning all selected
2260 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2261 _session->locations()->add (location, true);
2263 XMLNode &after = _session->locations()->get_state();
2264 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2266 commit_reversible_command ();
2272 Editor::jump_forward_to_mark ()
2278 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2284 _session->request_locate (pos, _session->transport_rolling());
2288 Editor::jump_backward_to_mark ()
2294 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2300 _session->request_locate (pos, _session->transport_rolling());
2306 framepos_t const pos = _session->audible_frame ();
2309 _session->locations()->next_available_name (markername, "mark");
2311 if (!choose_new_marker_name (markername)) {
2315 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2319 Editor::clear_markers ()
2322 begin_reversible_command (_("clear markers"));
2324 XMLNode &before = _session->locations()->get_state();
2325 _session->locations()->clear_markers ();
2326 XMLNode &after = _session->locations()->get_state();
2327 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2329 commit_reversible_command ();
2334 Editor::clear_ranges ()
2337 begin_reversible_command (_("clear ranges"));
2339 XMLNode &before = _session->locations()->get_state();
2341 _session->locations()->clear_ranges ();
2343 XMLNode &after = _session->locations()->get_state();
2344 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2346 commit_reversible_command ();
2351 Editor::clear_locations ()
2353 begin_reversible_command (_("clear locations"));
2355 XMLNode &before = _session->locations()->get_state();
2356 _session->locations()->clear ();
2357 XMLNode &after = _session->locations()->get_state();
2358 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2360 commit_reversible_command ();
2364 Editor::unhide_markers ()
2366 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2367 Location *l = (*i).first;
2368 if (l->is_hidden() && l->is_mark()) {
2369 l->set_hidden(false, this);
2375 Editor::unhide_ranges ()
2377 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2378 Location *l = (*i).first;
2379 if (l->is_hidden() && l->is_range_marker()) {
2380 l->set_hidden(false, this);
2385 /* INSERT/REPLACE */
2388 Editor::insert_region_list_selection (float times)
2390 RouteTimeAxisView *tv = 0;
2391 boost::shared_ptr<Playlist> playlist;
2393 if (clicked_routeview != 0) {
2394 tv = clicked_routeview;
2395 } else if (!selection->tracks.empty()) {
2396 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2399 } else if (entered_track != 0) {
2400 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2407 if ((playlist = tv->playlist()) == 0) {
2411 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2416 begin_reversible_command (_("insert region"));
2417 playlist->clear_changes ();
2418 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2419 if (Config->get_edit_mode() == Ripple)
2420 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2422 _session->add_command(new StatefulDiffCommand (playlist));
2423 commit_reversible_command ();
2426 /* BUILT-IN EFFECTS */
2429 Editor::reverse_selection ()
2434 /* GAIN ENVELOPE EDITING */
2437 Editor::edit_envelope ()
2444 Editor::transition_to_rolling (bool fwd)
2450 if (_session->config.get_external_sync()) {
2451 switch (Config->get_sync_source()) {
2455 /* transport controlled by the master */
2460 if (_session->is_auditioning()) {
2461 _session->cancel_audition ();
2465 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2469 Editor::play_from_start ()
2471 _session->request_locate (_session->current_start_frame(), true);
2475 Editor::play_from_edit_point ()
2477 _session->request_locate (get_preferred_edit_position(), true);
2481 Editor::play_from_edit_point_and_return ()
2483 framepos_t start_frame;
2484 framepos_t return_frame;
2486 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2488 if (_session->transport_rolling()) {
2489 _session->request_locate (start_frame, false);
2493 /* don't reset the return frame if its already set */
2495 if ((return_frame = _session->requested_return_frame()) < 0) {
2496 return_frame = _session->audible_frame();
2499 if (start_frame >= 0) {
2500 _session->request_roll_at_and_return (start_frame, return_frame);
2505 Editor::play_selection ()
2507 framepos_t start, end;
2508 if (!get_selection_extents ( start, end))
2511 AudioRange ar (start, end, 0);
2512 list<AudioRange> lar;
2515 _session->request_play_range (&lar, true);
2519 Editor::get_preroll ()
2521 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2526 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2528 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2531 location -= get_preroll();
2533 //don't try to locate before the beginning of time
2537 //if follow_playhead is on, keep the playhead on the screen
2538 if ( _follow_playhead )
2539 if ( location < leftmost_frame )
2540 location = leftmost_frame;
2542 _session->request_locate( location );
2546 Editor::play_with_preroll ()
2549 framepos_t preroll = get_preroll();
2551 framepos_t start, end;
2552 if (!get_selection_extents ( start, end))
2555 if (start > preroll)
2556 start = start - preroll;
2558 end = end + preroll; //"post-roll"
2560 AudioRange ar (start, end, 0);
2561 list<AudioRange> lar;
2564 _session->request_play_range (&lar, true);
2569 Editor::play_location (Location& location)
2571 if (location.start() <= location.end()) {
2575 _session->request_bounded_roll (location.start(), location.end());
2579 Editor::loop_location (Location& location)
2581 if (location.start() <= location.end()) {
2587 if ((tll = transport_loop_location()) != 0) {
2588 tll->set (location.start(), location.end());
2590 // enable looping, reposition and start rolling
2591 _session->request_locate (tll->start(), true);
2592 _session->request_play_loop (true);
2597 Editor::do_layer_operation (LayerOperation op)
2599 if (selection->regions.empty ()) {
2603 bool const multiple = selection->regions.size() > 1;
2607 begin_reversible_command (_("raise regions"));
2609 begin_reversible_command (_("raise region"));
2615 begin_reversible_command (_("raise regions to top"));
2617 begin_reversible_command (_("raise region to top"));
2623 begin_reversible_command (_("lower regions"));
2625 begin_reversible_command (_("lower region"));
2631 begin_reversible_command (_("lower regions to bottom"));
2633 begin_reversible_command (_("lower region"));
2638 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2639 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2640 (*i)->clear_owned_changes ();
2643 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2644 boost::shared_ptr<Region> r = (*i)->region ();
2656 r->lower_to_bottom ();
2660 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2661 vector<Command*> cmds;
2663 _session->add_commands (cmds);
2666 commit_reversible_command ();
2670 Editor::raise_region ()
2672 do_layer_operation (Raise);
2676 Editor::raise_region_to_top ()
2678 do_layer_operation (RaiseToTop);
2682 Editor::lower_region ()
2684 do_layer_operation (Lower);
2688 Editor::lower_region_to_bottom ()
2690 do_layer_operation (LowerToBottom);
2693 /** Show the region editor for the selected regions */
2695 Editor::show_region_properties ()
2697 selection->foreach_regionview (&RegionView::show_region_editor);
2700 /** Show the midi list editor for the selected MIDI regions */
2702 Editor::show_midi_list_editor ()
2704 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2708 Editor::rename_region ()
2710 RegionSelection rs = get_regions_from_selection_and_entered ();
2716 ArdourDialog d (*this, _("Rename Region"), true, false);
2718 Label label (_("New name:"));
2721 hbox.set_spacing (6);
2722 hbox.pack_start (label, false, false);
2723 hbox.pack_start (entry, true, true);
2725 d.get_vbox()->set_border_width (12);
2726 d.get_vbox()->pack_start (hbox, false, false);
2728 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2729 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2731 d.set_size_request (300, -1);
2733 entry.set_text (rs.front()->region()->name());
2734 entry.select_region (0, -1);
2736 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2742 int const ret = d.run();
2746 if (ret != RESPONSE_OK) {
2750 std::string str = entry.get_text();
2751 strip_whitespace_edges (str);
2753 rs.front()->region()->set_name (str);
2754 _regions->redisplay ();
2759 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2761 if (_session->is_auditioning()) {
2762 _session->cancel_audition ();
2765 // note: some potential for creativity here, because region doesn't
2766 // have to belong to the playlist that Route is handling
2768 // bool was_soloed = route.soloed();
2770 route.set_solo (true, this);
2772 _session->request_bounded_roll (region->position(), region->position() + region->length());
2774 /* XXX how to unset the solo state ? */
2777 /** Start an audition of the first selected region */
2779 Editor::play_edit_range ()
2781 framepos_t start, end;
2783 if (get_edit_op_range (start, end)) {
2784 _session->request_bounded_roll (start, end);
2789 Editor::play_selected_region ()
2791 framepos_t start = max_framepos;
2794 RegionSelection rs = get_regions_from_selection_and_entered ();
2800 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2801 if ((*i)->region()->position() < start) {
2802 start = (*i)->region()->position();
2804 if ((*i)->region()->last_frame() + 1 > end) {
2805 end = (*i)->region()->last_frame() + 1;
2809 _session->request_bounded_roll (start, end);
2813 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2815 _session->audition_region (region);
2819 Editor::region_from_selection ()
2821 if (clicked_axisview == 0) {
2825 if (selection->time.empty()) {
2829 framepos_t start = selection->time[clicked_selection].start;
2830 framepos_t end = selection->time[clicked_selection].end;
2832 TrackViewList tracks = get_tracks_for_range_action ();
2834 framepos_t selection_cnt = end - start + 1;
2836 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2837 boost::shared_ptr<Region> current;
2838 boost::shared_ptr<Playlist> pl;
2839 framepos_t internal_start;
2842 if ((pl = (*i)->playlist()) == 0) {
2846 if ((current = pl->top_region_at (start)) == 0) {
2850 internal_start = start - current->position();
2851 RegionFactory::region_name (new_name, current->name(), true);
2855 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2856 plist.add (ARDOUR::Properties::length, selection_cnt);
2857 plist.add (ARDOUR::Properties::name, new_name);
2858 plist.add (ARDOUR::Properties::layer, 0);
2860 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2865 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2867 if (selection->time.empty() || selection->tracks.empty()) {
2871 framepos_t start, end;
2872 if (clicked_selection) {
2873 start = selection->time[clicked_selection].start;
2874 end = selection->time[clicked_selection].end;
2876 start = selection->time.start();
2877 end = selection->time.end_frame();
2880 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2881 sort_track_selection (ts);
2883 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2884 boost::shared_ptr<Region> current;
2885 boost::shared_ptr<Playlist> playlist;
2886 framepos_t internal_start;
2889 if ((playlist = (*i)->playlist()) == 0) {
2893 if ((current = playlist->top_region_at(start)) == 0) {
2897 internal_start = start - current->position();
2898 RegionFactory::region_name (new_name, current->name(), true);
2902 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2903 plist.add (ARDOUR::Properties::length, end - start + 1);
2904 plist.add (ARDOUR::Properties::name, new_name);
2906 new_regions.push_back (RegionFactory::create (current, plist));
2911 Editor::split_multichannel_region ()
2913 RegionSelection rs = get_regions_from_selection_and_entered ();
2919 vector< boost::shared_ptr<Region> > v;
2921 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2922 (*x)->region()->separate_by_channel (*_session, v);
2927 Editor::new_region_from_selection ()
2929 region_from_selection ();
2930 cancel_selection ();
2934 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2936 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2937 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2938 case Evoral::OverlapNone:
2946 * - selected tracks, or if there are none...
2947 * - tracks containing selected regions, or if there are none...
2952 Editor::get_tracks_for_range_action () const
2956 if (selection->tracks.empty()) {
2958 /* use tracks with selected regions */
2960 RegionSelection rs = selection->regions;
2962 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2963 TimeAxisView* tv = &(*i)->get_time_axis_view();
2965 if (!t.contains (tv)) {
2971 /* no regions and no tracks: use all tracks */
2977 t = selection->tracks;
2980 return t.filter_to_unique_playlists();
2984 Editor::separate_regions_between (const TimeSelection& ts)
2986 bool in_command = false;
2987 boost::shared_ptr<Playlist> playlist;
2988 RegionSelection new_selection;
2990 TrackViewList tmptracks = get_tracks_for_range_action ();
2991 sort_track_selection (tmptracks);
2993 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2995 RouteTimeAxisView* rtv;
2997 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2999 if (rtv->is_track()) {
3001 /* no edits to destructive tracks */
3003 if (rtv->track()->destructive()) {
3007 if ((playlist = rtv->playlist()) != 0) {
3009 playlist->clear_changes ();
3011 /* XXX need to consider musical time selections here at some point */
3013 double speed = rtv->track()->speed();
3016 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3018 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3019 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3021 latest_regionviews.clear ();
3023 playlist->partition ((framepos_t)((*t).start * speed),
3024 (framepos_t)((*t).end * speed), false);
3028 if (!latest_regionviews.empty()) {
3030 rtv->view()->foreach_regionview (sigc::bind (
3031 sigc::ptr_fun (add_if_covered),
3032 &(*t), &new_selection));
3035 begin_reversible_command (_("separate"));
3039 /* pick up changes to existing regions */
3041 vector<Command*> cmds;
3042 playlist->rdiff (cmds);
3043 _session->add_commands (cmds);
3045 /* pick up changes to the playlist itself (adds/removes)
3048 _session->add_command(new StatefulDiffCommand (playlist));
3057 // selection->set (new_selection);
3059 commit_reversible_command ();
3063 struct PlaylistState {
3064 boost::shared_ptr<Playlist> playlist;
3068 /** Take tracks from get_tracks_for_range_action and cut any regions
3069 * on those tracks so that the tracks are empty over the time
3073 Editor::separate_region_from_selection ()
3075 /* preferentially use *all* ranges in the time selection if we're in range mode
3076 to allow discontiguous operation, since get_edit_op_range() currently
3077 returns a single range.
3080 if (!selection->time.empty()) {
3082 separate_regions_between (selection->time);
3089 if (get_edit_op_range (start, end)) {
3091 AudioRange ar (start, end, 1);
3095 separate_regions_between (ts);
3101 Editor::separate_region_from_punch ()
3103 Location* loc = _session->locations()->auto_punch_location();
3105 separate_regions_using_location (*loc);
3110 Editor::separate_region_from_loop ()
3112 Location* loc = _session->locations()->auto_loop_location();
3114 separate_regions_using_location (*loc);
3119 Editor::separate_regions_using_location (Location& loc)
3121 if (loc.is_mark()) {
3125 AudioRange ar (loc.start(), loc.end(), 1);
3130 separate_regions_between (ts);
3133 /** Separate regions under the selected region */
3135 Editor::separate_under_selected_regions ()
3137 vector<PlaylistState> playlists;
3141 rs = get_regions_from_selection_and_entered();
3143 if (!_session || rs.empty()) {
3147 begin_reversible_command (_("separate region under"));
3149 list<boost::shared_ptr<Region> > regions_to_remove;
3151 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3152 // we can't just remove the region(s) in this loop because
3153 // this removes them from the RegionSelection, and they thus
3154 // disappear from underneath the iterator, and the ++i above
3155 // SEGVs in a puzzling fashion.
3157 // so, first iterate over the regions to be removed from rs and
3158 // add them to the regions_to_remove list, and then
3159 // iterate over the list to actually remove them.
3161 regions_to_remove.push_back ((*i)->region());
3164 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3166 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3169 // is this check necessary?
3173 vector<PlaylistState>::iterator i;
3175 //only take state if this is a new playlist.
3176 for (i = playlists.begin(); i != playlists.end(); ++i) {
3177 if ((*i).playlist == playlist) {
3182 if (i == playlists.end()) {
3184 PlaylistState before;
3185 before.playlist = playlist;
3186 before.before = &playlist->get_state();
3188 playlist->freeze ();
3189 playlists.push_back(before);
3192 //Partition on the region bounds
3193 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3195 //Re-add region that was just removed due to the partition operation
3196 playlist->add_region( (*rl), (*rl)->first_frame() );
3199 vector<PlaylistState>::iterator pl;
3201 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3202 (*pl).playlist->thaw ();
3203 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3206 commit_reversible_command ();
3210 Editor::crop_region_to_selection ()
3212 if (!selection->time.empty()) {
3214 crop_region_to (selection->time.start(), selection->time.end_frame());
3221 if (get_edit_op_range (start, end)) {
3222 crop_region_to (start, end);
3229 Editor::crop_region_to (framepos_t start, framepos_t end)
3231 vector<boost::shared_ptr<Playlist> > playlists;
3232 boost::shared_ptr<Playlist> playlist;
3235 if (selection->tracks.empty()) {
3236 ts = track_views.filter_to_unique_playlists();
3238 ts = selection->tracks.filter_to_unique_playlists ();
3241 sort_track_selection (ts);
3243 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3245 RouteTimeAxisView* rtv;
3247 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3249 boost::shared_ptr<Track> t = rtv->track();
3251 if (t != 0 && ! t->destructive()) {
3253 if ((playlist = rtv->playlist()) != 0) {
3254 playlists.push_back (playlist);
3260 if (playlists.empty()) {
3264 framepos_t the_start;
3268 begin_reversible_command (_("trim to selection"));
3270 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3272 boost::shared_ptr<Region> region;
3276 if ((region = (*i)->top_region_at(the_start)) == 0) {
3280 /* now adjust lengths to that we do the right thing
3281 if the selection extends beyond the region
3284 the_start = max (the_start, (framepos_t) region->position());
3285 if (max_framepos - the_start < region->length()) {
3286 the_end = the_start + region->length() - 1;
3288 the_end = max_framepos;
3290 the_end = min (end, the_end);
3291 cnt = the_end - the_start + 1;
3293 region->clear_changes ();
3294 region->trim_to (the_start, cnt);
3295 _session->add_command (new StatefulDiffCommand (region));
3298 commit_reversible_command ();
3302 Editor::region_fill_track ()
3304 RegionSelection rs = get_regions_from_selection_and_entered ();
3306 if (!_session || rs.empty()) {
3310 framepos_t const end = _session->current_end_frame ();
3312 begin_reversible_command (Operations::region_fill);
3314 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3316 boost::shared_ptr<Region> region ((*i)->region());
3318 boost::shared_ptr<Playlist> pl = region->playlist();
3320 if (end <= region->last_frame()) {
3324 double times = (double) (end - region->last_frame()) / (double) region->length();
3330 pl->clear_changes ();
3331 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3332 _session->add_command (new StatefulDiffCommand (pl));
3335 commit_reversible_command ();
3339 Editor::region_fill_selection ()
3341 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3345 if (selection->time.empty()) {
3349 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3354 framepos_t start = selection->time[clicked_selection].start;
3355 framepos_t end = selection->time[clicked_selection].end;
3357 boost::shared_ptr<Playlist> playlist;
3359 if (selection->tracks.empty()) {
3363 framepos_t selection_length = end - start;
3364 float times = (float)selection_length / region->length();
3366 begin_reversible_command (Operations::fill_selection);
3368 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3370 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3372 if ((playlist = (*i)->playlist()) == 0) {
3376 playlist->clear_changes ();
3377 playlist->add_region (RegionFactory::create (region, true), start, times);
3378 _session->add_command (new StatefulDiffCommand (playlist));
3381 commit_reversible_command ();
3385 Editor::set_region_sync_position ()
3387 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3391 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3393 bool in_command = false;
3395 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3397 if (!(*r)->region()->covers (where)) {
3401 boost::shared_ptr<Region> region ((*r)->region());
3404 begin_reversible_command (_("set sync point"));
3408 region->clear_changes ();
3409 region->set_sync_position (where);
3410 _session->add_command(new StatefulDiffCommand (region));
3414 commit_reversible_command ();
3418 /** Remove the sync positions of the selection */
3420 Editor::remove_region_sync ()
3422 RegionSelection rs = get_regions_from_selection_and_entered ();
3428 begin_reversible_command (_("remove region sync"));
3430 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3432 (*i)->region()->clear_changes ();
3433 (*i)->region()->clear_sync_position ();
3434 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3437 commit_reversible_command ();
3441 Editor::naturalize_region ()
3443 RegionSelection rs = get_regions_from_selection_and_entered ();
3449 if (rs.size() > 1) {
3450 begin_reversible_command (_("move regions to original position"));
3452 begin_reversible_command (_("move region to original position"));
3455 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3456 (*i)->region()->clear_changes ();
3457 (*i)->region()->move_to_natural_position ();
3458 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3461 commit_reversible_command ();
3465 Editor::align_regions (RegionPoint what)
3467 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3473 begin_reversible_command (_("align selection"));
3475 framepos_t const position = get_preferred_edit_position ();
3477 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3478 align_region_internal ((*i)->region(), what, position);
3481 commit_reversible_command ();
3484 struct RegionSortByTime {
3485 bool operator() (const RegionView* a, const RegionView* b) {
3486 return a->region()->position() < b->region()->position();
3491 Editor::align_regions_relative (RegionPoint point)
3493 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3499 framepos_t const position = get_preferred_edit_position ();
3501 framepos_t distance = 0;
3505 list<RegionView*> sorted;
3506 rs.by_position (sorted);
3508 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3513 if (position > r->position()) {
3514 distance = position - r->position();
3516 distance = r->position() - position;
3522 if (position > r->last_frame()) {
3523 distance = position - r->last_frame();
3524 pos = r->position() + distance;
3526 distance = r->last_frame() - position;
3527 pos = r->position() - distance;
3533 pos = r->adjust_to_sync (position);
3534 if (pos > r->position()) {
3535 distance = pos - r->position();
3537 distance = r->position() - pos;
3543 if (pos == r->position()) {
3547 begin_reversible_command (_("align selection (relative)"));
3549 /* move first one specially */
3551 r->clear_changes ();
3552 r->set_position (pos);
3553 _session->add_command(new StatefulDiffCommand (r));
3555 /* move rest by the same amount */
3559 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3561 boost::shared_ptr<Region> region ((*i)->region());
3563 region->clear_changes ();
3566 region->set_position (region->position() + distance);
3568 region->set_position (region->position() - distance);
3571 _session->add_command(new StatefulDiffCommand (region));
3575 commit_reversible_command ();
3579 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3581 begin_reversible_command (_("align region"));
3582 align_region_internal (region, point, position);
3583 commit_reversible_command ();
3587 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3589 region->clear_changes ();
3593 region->set_position (region->adjust_to_sync (position));
3597 if (position > region->length()) {
3598 region->set_position (position - region->length());
3603 region->set_position (position);
3607 _session->add_command(new StatefulDiffCommand (region));
3611 Editor::trim_region_front ()
3617 Editor::trim_region_back ()
3619 trim_region (false);
3623 Editor::trim_region (bool front)
3625 framepos_t where = get_preferred_edit_position();
3626 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3632 begin_reversible_command (front ? _("trim front") : _("trim back"));
3634 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3635 if (!(*i)->region()->locked()) {
3637 (*i)->region()->clear_changes ();
3640 (*i)->region()->trim_front (where);
3641 maybe_locate_with_edit_preroll ( where );
3643 (*i)->region()->trim_end (where);
3644 maybe_locate_with_edit_preroll ( where );
3647 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3651 commit_reversible_command ();
3654 /** Trim the end of the selected regions to the position of the edit cursor */
3656 Editor::trim_region_to_loop ()
3658 Location* loc = _session->locations()->auto_loop_location();
3662 trim_region_to_location (*loc, _("trim to loop"));
3666 Editor::trim_region_to_punch ()
3668 Location* loc = _session->locations()->auto_punch_location();
3672 trim_region_to_location (*loc, _("trim to punch"));
3676 Editor::trim_region_to_location (const Location& loc, const char* str)
3678 RegionSelection rs = get_regions_from_selection_and_entered ();
3680 begin_reversible_command (str);
3682 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3683 RegionView* rv = (*x);
3685 /* require region to span proposed trim */
3686 switch (rv->region()->coverage (loc.start(), loc.end())) {
3687 case Evoral::OverlapInternal:
3693 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3702 if (tav->track() != 0) {
3703 speed = tav->track()->speed();
3706 start = session_frame_to_track_frame (loc.start(), speed);
3707 end = session_frame_to_track_frame (loc.end(), speed);
3709 rv->region()->clear_changes ();
3710 rv->region()->trim_to (start, (end - start));
3711 _session->add_command(new StatefulDiffCommand (rv->region()));
3714 commit_reversible_command ();
3718 Editor::trim_region_to_previous_region_end ()
3720 return trim_to_region(false);
3724 Editor::trim_region_to_next_region_start ()
3726 return trim_to_region(true);
3730 Editor::trim_to_region(bool forward)
3732 RegionSelection rs = get_regions_from_selection_and_entered ();
3734 begin_reversible_command (_("trim to region"));
3736 boost::shared_ptr<Region> next_region;
3738 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3740 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3746 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3754 if (atav->track() != 0) {
3755 speed = atav->track()->speed();
3759 boost::shared_ptr<Region> region = arv->region();
3760 boost::shared_ptr<Playlist> playlist (region->playlist());
3762 region->clear_changes ();
3766 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3772 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3773 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3777 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3783 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3785 arv->region_changed (ARDOUR::bounds_change);
3788 _session->add_command(new StatefulDiffCommand (region));
3791 commit_reversible_command ();
3795 Editor::unfreeze_route ()
3797 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3801 clicked_routeview->track()->unfreeze ();
3805 Editor::_freeze_thread (void* arg)
3807 return static_cast<Editor*>(arg)->freeze_thread ();
3811 Editor::freeze_thread ()
3813 /* create event pool because we may need to talk to the session */
3814 SessionEvent::create_per_thread_pool ("freeze events", 64);
3815 /* create per-thread buffers for process() tree to use */
3816 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3817 current_interthread_info->done = true;
3822 Editor::freeze_route ()
3828 /* stop transport before we start. this is important */
3830 _session->request_transport_speed (0.0);
3832 /* wait for just a little while, because the above call is asynchronous */
3834 Glib::usleep (250000);
3836 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3840 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3842 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3843 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3845 d.set_title (_("Cannot freeze"));
3850 if (clicked_routeview->track()->has_external_redirects()) {
3851 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"
3852 "Freezing will only process the signal as far as the first send/insert/return."),
3853 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3855 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3856 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3857 d.set_title (_("Freeze Limits"));
3859 int response = d.run ();
3862 case Gtk::RESPONSE_CANCEL:
3869 InterThreadInfo itt;
3870 current_interthread_info = &itt;
3872 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3874 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3876 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3878 while (!itt.done && !itt.cancel) {
3879 gtk_main_iteration ();
3882 current_interthread_info = 0;
3886 Editor::bounce_range_selection (bool replace, bool enable_processing)
3888 if (selection->time.empty()) {
3892 TrackSelection views = selection->tracks;
3894 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3896 if (enable_processing) {
3898 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3900 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3902 _("You can't perform this operation because the processing of the signal "
3903 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3904 "You can do this without processing, which is a different operation.")
3906 d.set_title (_("Cannot bounce"));
3913 framepos_t start = selection->time[clicked_selection].start;
3914 framepos_t end = selection->time[clicked_selection].end;
3915 framepos_t cnt = end - start + 1;
3917 begin_reversible_command (_("bounce range"));
3919 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3921 RouteTimeAxisView* rtv;
3923 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3927 boost::shared_ptr<Playlist> playlist;
3929 if ((playlist = rtv->playlist()) == 0) {
3933 InterThreadInfo itt;
3935 playlist->clear_changes ();
3936 playlist->clear_owned_changes ();
3938 boost::shared_ptr<Region> r;
3940 if (enable_processing) {
3941 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3943 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3951 list<AudioRange> ranges;
3952 ranges.push_back (AudioRange (start, start+cnt, 0));
3953 playlist->cut (ranges); // discard result
3954 playlist->add_region (r, start);
3957 vector<Command*> cmds;
3958 playlist->rdiff (cmds);
3959 _session->add_commands (cmds);
3961 _session->add_command (new StatefulDiffCommand (playlist));
3964 commit_reversible_command ();
3967 /** Delete selected regions, automation points or a time range */
3971 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3972 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3973 bool deleted = false;
3974 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3975 deleted = current_mixer_strip->delete_processors ();
3981 /** Cut selected regions, automation points or a time range */
3988 /** Copy selected regions, automation points or a time range */
3996 /** @return true if a Cut, Copy or Clear is possible */
3998 Editor::can_cut_copy () const
4000 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4007 /** Cut, copy or clear selected regions, automation points or a time range.
4008 * @param op Operation (Delete, Cut, Copy or Clear)
4011 Editor::cut_copy (CutCopyOp op)
4013 /* only cancel selection if cut/copy is successful.*/
4019 opname = _("delete");
4028 opname = _("clear");
4032 /* if we're deleting something, and the mouse is still pressed,
4033 the thing we started a drag for will be gone when we release
4034 the mouse button(s). avoid this. see part 2 at the end of
4038 if (op == Delete || op == Cut || op == Clear) {
4039 if (_drags->active ()) {
4044 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4045 cut_buffer->clear ();
4047 if (entered_marker) {
4049 /* cut/delete op while pointing at a marker */
4052 Location* loc = find_location_from_marker (entered_marker, ignored);
4054 if (_session && loc) {
4055 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4062 switch (mouse_mode) {
4065 begin_reversible_command (opname + ' ' + X_("MIDI"));
4067 commit_reversible_command ();
4073 bool did_edit = false;
4075 if (!selection->regions.empty() || !selection->points.empty()) {
4076 begin_reversible_command (opname + ' ' + _("objects"));
4079 if (!selection->regions.empty()) {
4080 cut_copy_regions (op, selection->regions);
4082 if (op == Cut || op == Delete) {
4083 selection->clear_regions ();
4087 if (!selection->points.empty()) {
4088 cut_copy_points (op);
4090 if (op == Cut || op == Delete) {
4091 selection->clear_points ();
4094 } else if (selection->time.empty()) {
4095 framepos_t start, end;
4096 /* no time selection, see if we can get an edit range
4099 if (get_edit_op_range (start, end)) {
4100 selection->set (start, end);
4102 } else if (!selection->time.empty()) {
4103 begin_reversible_command (opname + ' ' + _("range"));
4106 cut_copy_ranges (op);
4108 if (op == Cut || op == Delete) {
4109 selection->clear_time ();
4114 /* reset repeated paste state */
4117 commit_reversible_command ();
4120 if (op == Delete || op == Cut || op == Clear) {
4125 struct AutomationRecord {
4126 AutomationRecord () : state (0) , line(NULL) {}
4127 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4129 XMLNode* state; ///< state before any operation
4130 const AutomationLine* line; ///< line this came from
4131 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4134 /** Cut, copy or clear selected automation points.
4135 * @param op Operation (Cut, Copy or Clear)
4138 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4140 if (selection->points.empty ()) {
4144 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4145 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4147 /* Keep a record of the AutomationLists that we end up using in this operation */
4148 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4151 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4152 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4153 const AutomationLine& line = (*i)->line();
4154 const boost::shared_ptr<AutomationList> al = line.the_list();
4155 if (lists.find (al) == lists.end ()) {
4156 /* We haven't seen this list yet, so make a record for it. This includes
4157 taking a copy of its current state, in case this is needed for undo later.
4159 lists[al] = AutomationRecord (&al->get_state (), &line);
4163 if (op == Cut || op == Copy) {
4164 /* This operation will involve putting things in the cut buffer, so create an empty
4165 ControlList for each of our source lists to put the cut buffer data in.
4167 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4168 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4171 /* Add all selected points to the relevant copy ControlLists */
4172 framepos_t start = std::numeric_limits<framepos_t>::max();
4173 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4174 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4175 AutomationList::const_iterator j = (*i)->model();
4177 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4179 /* Update earliest MIDI start time in beats */
4180 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4182 /* Update earliest session start time in frames */
4183 start = std::min(start, (*i)->line().session_position(j));
4187 /* Snap start time backwards, so copy/paste is snap aligned. */
4189 if (earliest == Evoral::Beats::max()) {
4190 earliest = Evoral::Beats(); // Weird... don't offset
4192 earliest.round_down_to_beat();
4194 if (start == std::numeric_limits<double>::max()) {
4195 start = 0; // Weird... don't offset
4197 snap_to(start, RoundDownMaybe);
4200 const double line_offset = midi ? earliest.to_double() : start;
4201 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4202 /* Correct this copy list so that it is relative to the earliest
4203 start time, so relative ordering between points is preserved
4204 when copying from several lists and the paste starts at the
4205 earliest copied piece of data. */
4206 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4207 (*j)->when -= line_offset;
4210 /* And add it to the cut buffer */
4211 cut_buffer->add (i->second.copy);
4215 if (op == Delete || op == Cut) {
4216 /* This operation needs to remove things from the main AutomationList, so do that now */
4218 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4219 i->first->freeze ();
4222 /* Remove each selected point from its AutomationList */
4223 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4224 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4225 al->erase ((*i)->model ());
4228 /* Thaw the lists and add undo records for them */
4229 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4230 boost::shared_ptr<AutomationList> al = i->first;
4232 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4237 /** Cut, copy or clear selected automation points.
4238 * @param op Operation (Cut, Copy or Clear)
4241 Editor::cut_copy_midi (CutCopyOp op)
4243 Evoral::Beats earliest = Evoral::Beats::max();
4244 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4245 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4247 if (!mrv->selection().empty()) {
4248 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4250 mrv->cut_copy_clear (op);
4252 /* XXX: not ideal, as there may be more than one track involved in the selection */
4253 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4257 if (!selection->points.empty()) {
4258 cut_copy_points (op, earliest, true);
4259 if (op == Cut || op == Delete) {
4260 selection->clear_points ();
4265 struct lt_playlist {
4266 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4267 return a.playlist < b.playlist;
4271 struct PlaylistMapping {
4273 boost::shared_ptr<Playlist> pl;
4275 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4278 /** Remove `clicked_regionview' */
4280 Editor::remove_clicked_region ()
4282 if (clicked_routeview == 0 || clicked_regionview == 0) {
4286 begin_reversible_command (_("remove region"));
4288 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4290 playlist->clear_changes ();
4291 playlist->clear_owned_changes ();
4292 playlist->remove_region (clicked_regionview->region());
4293 if (Config->get_edit_mode() == Ripple)
4294 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4296 /* We might have removed regions, which alters other regions' layering_index,
4297 so we need to do a recursive diff here.
4299 vector<Command*> cmds;
4300 playlist->rdiff (cmds);
4301 _session->add_commands (cmds);
4303 _session->add_command(new StatefulDiffCommand (playlist));
4304 commit_reversible_command ();
4308 /** Remove the selected regions */
4310 Editor::remove_selected_regions ()
4312 RegionSelection rs = get_regions_from_selection_and_entered ();
4314 if (!_session || rs.empty()) {
4318 begin_reversible_command (_("remove region"));
4320 list<boost::shared_ptr<Region> > regions_to_remove;
4322 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4323 // we can't just remove the region(s) in this loop because
4324 // this removes them from the RegionSelection, and they thus
4325 // disappear from underneath the iterator, and the ++i above
4326 // SEGVs in a puzzling fashion.
4328 // so, first iterate over the regions to be removed from rs and
4329 // add them to the regions_to_remove list, and then
4330 // iterate over the list to actually remove them.
4332 regions_to_remove.push_back ((*i)->region());
4335 vector<boost::shared_ptr<Playlist> > playlists;
4337 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4339 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4342 // is this check necessary?
4346 /* get_regions_from_selection_and_entered() guarantees that
4347 the playlists involved are unique, so there is no need
4351 playlists.push_back (playlist);
4353 playlist->clear_changes ();
4354 playlist->clear_owned_changes ();
4355 playlist->freeze ();
4356 playlist->remove_region (*rl);
4357 if (Config->get_edit_mode() == Ripple)
4358 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4362 vector<boost::shared_ptr<Playlist> >::iterator pl;
4364 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4367 /* We might have removed regions, which alters other regions' layering_index,
4368 so we need to do a recursive diff here.
4370 vector<Command*> cmds;
4371 (*pl)->rdiff (cmds);
4372 _session->add_commands (cmds);
4374 _session->add_command(new StatefulDiffCommand (*pl));
4377 commit_reversible_command ();
4380 /** Cut, copy or clear selected regions.
4381 * @param op Operation (Cut, Copy or Clear)
4384 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4386 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4387 a map when we want ordered access to both elements. i think.
4390 vector<PlaylistMapping> pmap;
4392 framepos_t first_position = max_framepos;
4394 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4395 FreezeList freezelist;
4397 /* get ordering correct before we cut/copy */
4399 rs.sort_by_position_and_track ();
4401 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4403 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4405 if (op == Cut || op == Clear || op == Delete) {
4406 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4409 FreezeList::iterator fl;
4411 // only take state if this is a new playlist.
4412 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4418 if (fl == freezelist.end()) {
4419 pl->clear_changes();
4420 pl->clear_owned_changes ();
4422 freezelist.insert (pl);
4427 TimeAxisView* tv = &(*x)->get_time_axis_view();
4428 vector<PlaylistMapping>::iterator z;
4430 for (z = pmap.begin(); z != pmap.end(); ++z) {
4431 if ((*z).tv == tv) {
4436 if (z == pmap.end()) {
4437 pmap.push_back (PlaylistMapping (tv));
4441 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4443 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4446 /* region not yet associated with a playlist (e.g. unfinished
4453 TimeAxisView& tv = (*x)->get_time_axis_view();
4454 boost::shared_ptr<Playlist> npl;
4455 RegionSelection::iterator tmp;
4462 vector<PlaylistMapping>::iterator z;
4464 for (z = pmap.begin(); z != pmap.end(); ++z) {
4465 if ((*z).tv == &tv) {
4470 assert (z != pmap.end());
4473 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4481 boost::shared_ptr<Region> r = (*x)->region();
4482 boost::shared_ptr<Region> _xx;
4488 pl->remove_region (r);
4489 if (Config->get_edit_mode() == Ripple)
4490 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4494 _xx = RegionFactory::create (r);
4495 npl->add_region (_xx, r->position() - first_position);
4496 pl->remove_region (r);
4497 if (Config->get_edit_mode() == Ripple)
4498 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4502 /* copy region before adding, so we're not putting same object into two different playlists */
4503 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4507 pl->remove_region (r);
4508 if (Config->get_edit_mode() == Ripple)
4509 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4518 list<boost::shared_ptr<Playlist> > foo;
4520 /* the pmap is in the same order as the tracks in which selected regions occured */
4522 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4525 foo.push_back ((*i).pl);
4530 cut_buffer->set (foo);
4534 _last_cut_copy_source_track = 0;
4536 _last_cut_copy_source_track = pmap.front().tv;
4540 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4543 /* We might have removed regions, which alters other regions' layering_index,
4544 so we need to do a recursive diff here.
4546 vector<Command*> cmds;
4547 (*pl)->rdiff (cmds);
4548 _session->add_commands (cmds);
4550 _session->add_command (new StatefulDiffCommand (*pl));
4555 Editor::cut_copy_ranges (CutCopyOp op)
4557 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4559 /* Sort the track selection now, so that it if is used, the playlists
4560 selected by the calls below to cut_copy_clear are in the order that
4561 their tracks appear in the editor. This makes things like paste
4562 of ranges work properly.
4565 sort_track_selection (ts);
4568 if (!entered_track) {
4571 ts.push_back (entered_track);
4574 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4575 (*i)->cut_copy_clear (*selection, op);
4580 Editor::paste (float times, bool from_context)
4582 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4584 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4588 Editor::mouse_paste ()
4593 if (!mouse_frame (where, ignored)) {
4598 paste_internal (where, 1);
4602 Editor::paste_internal (framepos_t position, float times)
4604 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4606 if (cut_buffer->empty(internal_editing())) {
4610 if (position == max_framepos) {
4611 position = get_preferred_edit_position();
4612 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4615 if (position == last_paste_pos) {
4616 /* repeated paste in the same position */
4619 /* paste in new location, reset repeated paste state */
4621 last_paste_pos = position;
4624 /* get everything in the correct order */
4627 if (!selection->tracks.empty()) {
4628 /* If there is a track selection, paste into exactly those tracks and
4629 only those tracks. This allows the user to be explicit and override
4630 the below "do the reasonable thing" logic. */
4631 ts = selection->tracks.filter_to_unique_playlists ();
4632 sort_track_selection (ts);
4634 /* Figure out which track to base the paste at. */
4635 TimeAxisView* base_track = NULL;
4636 if (_edit_point == Editing::EditAtMouse && entered_track) {
4637 /* With the mouse edit point, paste onto the track under the mouse. */
4638 base_track = entered_track;
4639 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4640 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4641 base_track = &entered_regionview->get_time_axis_view();
4642 } else if (_last_cut_copy_source_track) {
4643 /* Paste to the track that the cut/copy came from (see mantis #333). */
4644 base_track = _last_cut_copy_source_track;
4646 /* This is "impossible" since we've copied... well, do nothing. */
4650 /* Walk up to parent if necessary, so base track is a route. */
4651 while (base_track->get_parent()) {
4652 base_track = base_track->get_parent();
4655 /* Add base track and all tracks below it. The paste logic will select
4656 the appropriate object types from the cut buffer in relative order. */
4657 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4658 if ((*i)->order() >= base_track->order()) {
4663 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4664 sort_track_selection (ts);
4666 /* Add automation children of each track in order, for pasting several lines. */
4667 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4668 /* Add any automation children for pasting several lines */
4669 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4674 typedef RouteTimeAxisView::AutomationTracks ATracks;
4675 const ATracks& atracks = rtv->automation_tracks();
4676 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4677 i = ts.insert(i, a->second.get());
4682 /* We now have a list of trackviews starting at base_track, including
4683 automation children, in the order shown in the editor, e.g. R1,
4684 R1.A1, R1.A2, R2, R2.A1, ... */
4687 begin_reversible_command (Operations::paste);
4689 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4690 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4691 /* Only one line copied, and one automation track selected. Do a
4692 "greedy" paste from one automation type to another. */
4694 PasteContext ctx(paste_count, times, ItemCounts(), true);
4695 ts.front()->paste (position, *cut_buffer, ctx);
4699 /* Paste into tracks */
4701 PasteContext ctx(paste_count, times, ItemCounts(), false);
4702 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4703 (*i)->paste (position, *cut_buffer, ctx);
4707 commit_reversible_command ();
4711 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4713 boost::shared_ptr<Playlist> playlist;
4714 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4715 RegionSelection foo;
4717 framepos_t const start_frame = regions.start ();
4718 framepos_t const end_frame = regions.end_frame ();
4720 begin_reversible_command (Operations::duplicate_region);
4722 selection->clear_regions ();
4724 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4726 boost::shared_ptr<Region> r ((*i)->region());
4728 TimeAxisView& tv = (*i)->get_time_axis_view();
4729 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4730 latest_regionviews.clear ();
4731 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4733 playlist = (*i)->region()->playlist();
4734 playlist->clear_changes ();
4735 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4736 _session->add_command(new StatefulDiffCommand (playlist));
4740 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4744 selection->set (foo);
4747 commit_reversible_command ();
4751 Editor::duplicate_selection (float times)
4753 if (selection->time.empty() || selection->tracks.empty()) {
4757 boost::shared_ptr<Playlist> playlist;
4758 vector<boost::shared_ptr<Region> > new_regions;
4759 vector<boost::shared_ptr<Region> >::iterator ri;
4761 create_region_from_selection (new_regions);
4763 if (new_regions.empty()) {
4767 begin_reversible_command (_("duplicate selection"));
4769 ri = new_regions.begin();
4771 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4773 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4774 if ((playlist = (*i)->playlist()) == 0) {
4777 playlist->clear_changes ();
4779 if (clicked_selection) {
4780 end = selection->time[clicked_selection].end;
4782 end = selection->time.end_frame();
4784 playlist->duplicate (*ri, end, times);
4785 _session->add_command (new StatefulDiffCommand (playlist));
4788 if (ri == new_regions.end()) {
4793 commit_reversible_command ();
4796 /** Reset all selected points to the relevant default value */
4798 Editor::reset_point_selection ()
4800 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4801 ARDOUR::AutomationList::iterator j = (*i)->model ();
4802 (*j)->value = (*i)->line().the_list()->default_value ();
4807 Editor::center_playhead ()
4809 float const page = _visible_canvas_width * samples_per_pixel;
4810 center_screen_internal (playhead_cursor->current_frame (), page);
4814 Editor::center_edit_point ()
4816 float const page = _visible_canvas_width * samples_per_pixel;
4817 center_screen_internal (get_preferred_edit_position(), page);
4820 /** Caller must begin and commit a reversible command */
4822 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4824 playlist->clear_changes ();
4826 _session->add_command (new StatefulDiffCommand (playlist));
4830 Editor::nudge_track (bool use_edit, bool forwards)
4832 boost::shared_ptr<Playlist> playlist;
4833 framepos_t distance;
4834 framepos_t next_distance;
4838 start = get_preferred_edit_position();
4843 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4847 if (selection->tracks.empty()) {
4851 begin_reversible_command (_("nudge track"));
4853 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4855 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4857 if ((playlist = (*i)->playlist()) == 0) {
4861 playlist->clear_changes ();
4862 playlist->clear_owned_changes ();
4864 playlist->nudge_after (start, distance, forwards);
4866 vector<Command*> cmds;
4868 playlist->rdiff (cmds);
4869 _session->add_commands (cmds);
4871 _session->add_command (new StatefulDiffCommand (playlist));
4874 commit_reversible_command ();
4878 Editor::remove_last_capture ()
4880 vector<string> choices;
4887 if (Config->get_verify_remove_last_capture()) {
4888 prompt = _("Do you really want to destroy the last capture?"
4889 "\n(This is destructive and cannot be undone)");
4891 choices.push_back (_("No, do nothing."));
4892 choices.push_back (_("Yes, destroy it."));
4894 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4896 if (prompter.run () == 1) {
4897 _session->remove_last_capture ();
4898 _regions->redisplay ();
4902 _session->remove_last_capture();
4903 _regions->redisplay ();
4908 Editor::normalize_region ()
4914 RegionSelection rs = get_regions_from_selection_and_entered ();
4920 NormalizeDialog dialog (rs.size() > 1);
4922 if (dialog.run () == RESPONSE_CANCEL) {
4926 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4929 /* XXX: should really only count audio regions here */
4930 int const regions = rs.size ();
4932 /* Make a list of the selected audio regions' maximum amplitudes, and also
4933 obtain the maximum amplitude of them all.
4935 list<double> max_amps;
4937 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4938 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4940 dialog.descend (1.0 / regions);
4941 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4944 /* the user cancelled the operation */
4948 max_amps.push_back (a);
4949 max_amp = max (max_amp, a);
4954 begin_reversible_command (_("normalize"));
4956 list<double>::const_iterator a = max_amps.begin ();
4958 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4959 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4964 arv->region()->clear_changes ();
4966 double const amp = dialog.normalize_individually() ? *a : max_amp;
4968 arv->audio_region()->normalize (amp, dialog.target ());
4969 _session->add_command (new StatefulDiffCommand (arv->region()));
4974 commit_reversible_command ();
4979 Editor::reset_region_scale_amplitude ()
4985 RegionSelection rs = get_regions_from_selection_and_entered ();
4991 begin_reversible_command ("reset gain");
4993 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4994 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4997 arv->region()->clear_changes ();
4998 arv->audio_region()->set_scale_amplitude (1.0f);
4999 _session->add_command (new StatefulDiffCommand (arv->region()));
5002 commit_reversible_command ();
5006 Editor::adjust_region_gain (bool up)
5008 RegionSelection rs = get_regions_from_selection_and_entered ();
5010 if (!_session || rs.empty()) {
5014 begin_reversible_command ("adjust region gain");
5016 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5017 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5022 arv->region()->clear_changes ();
5024 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5032 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5033 _session->add_command (new StatefulDiffCommand (arv->region()));
5036 commit_reversible_command ();
5041 Editor::reverse_region ()
5047 Reverse rev (*_session);
5048 apply_filter (rev, _("reverse regions"));
5052 Editor::strip_region_silence ()
5058 RegionSelection rs = get_regions_from_selection_and_entered ();
5064 std::list<RegionView*> audio_only;
5066 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5067 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5069 audio_only.push_back (arv);
5073 StripSilenceDialog d (_session, audio_only);
5074 int const r = d.run ();
5078 if (r == Gtk::RESPONSE_OK) {
5079 ARDOUR::AudioIntervalMap silences;
5080 d.silences (silences);
5081 StripSilence s (*_session, silences, d.fade_length());
5082 apply_filter (s, _("strip silence"), &d);
5087 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5089 Evoral::Sequence<Evoral::Beats>::Notes selected;
5090 mrv.selection_as_notelist (selected, true);
5092 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5093 v.push_back (selected);
5095 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5096 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5098 return op (mrv.midi_region()->model(), pos_beats, v);
5102 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5108 begin_reversible_command (op.name ());
5110 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5111 RegionSelection::const_iterator tmp = r;
5114 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5117 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5120 _session->add_command (cmd);
5127 commit_reversible_command ();
5131 Editor::fork_region ()
5133 RegionSelection rs = get_regions_from_selection_and_entered ();
5139 begin_reversible_command (_("Fork Region(s)"));
5141 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5144 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5145 RegionSelection::iterator tmp = r;
5148 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5152 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5153 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5154 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5156 playlist->clear_changes ();
5157 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5158 _session->add_command(new StatefulDiffCommand (playlist));
5160 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5167 commit_reversible_command ();
5171 Editor::quantize_region ()
5174 quantize_regions(get_regions_from_selection_and_entered ());
5179 Editor::quantize_regions (const RegionSelection& rs)
5181 if (rs.n_midi_regions() == 0) {
5185 if (!quantize_dialog) {
5186 quantize_dialog = new QuantizeDialog (*this);
5189 quantize_dialog->present ();
5190 const int r = quantize_dialog->run ();
5191 quantize_dialog->hide ();
5193 if (r == Gtk::RESPONSE_OK) {
5194 Quantize quant (quantize_dialog->snap_start(),
5195 quantize_dialog->snap_end(),
5196 quantize_dialog->start_grid_size(),
5197 quantize_dialog->end_grid_size(),
5198 quantize_dialog->strength(),
5199 quantize_dialog->swing(),
5200 quantize_dialog->threshold());
5202 apply_midi_note_edit_op (quant, rs);
5207 Editor::legatize_region (bool shrink_only)
5210 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5215 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5217 if (rs.n_midi_regions() == 0) {
5221 Legatize legatize(shrink_only);
5222 apply_midi_note_edit_op (legatize, rs);
5226 Editor::transform_region ()
5229 transform_regions(get_regions_from_selection_and_entered ());
5234 Editor::transform_regions (const RegionSelection& rs)
5236 if (rs.n_midi_regions() == 0) {
5240 TransformDialog* td = new TransformDialog();
5243 const int r = td->run();
5246 if (r == Gtk::RESPONSE_OK) {
5247 Transform transform(td->get());
5248 apply_midi_note_edit_op(transform, rs);
5253 Editor::insert_patch_change (bool from_context)
5255 RegionSelection rs = get_regions_from_selection_and_entered ();
5261 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5263 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5264 there may be more than one, but the PatchChangeDialog can only offer
5265 one set of patch menus.
5267 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5269 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5270 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5272 if (d.run() == RESPONSE_CANCEL) {
5276 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5277 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5279 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5280 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5287 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5289 RegionSelection rs = get_regions_from_selection_and_entered ();
5295 begin_reversible_command (command);
5297 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5301 int const N = rs.size ();
5303 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5304 RegionSelection::iterator tmp = r;
5307 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5309 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5312 progress->descend (1.0 / N);
5315 if (arv->audio_region()->apply (filter, progress) == 0) {
5317 playlist->clear_changes ();
5318 playlist->clear_owned_changes ();
5320 if (filter.results.empty ()) {
5322 /* no regions returned; remove the old one */
5323 playlist->remove_region (arv->region ());
5327 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5329 /* first region replaces the old one */
5330 playlist->replace_region (arv->region(), *res, (*res)->position());
5334 while (res != filter.results.end()) {
5335 playlist->add_region (*res, (*res)->position());
5341 /* We might have removed regions, which alters other regions' layering_index,
5342 so we need to do a recursive diff here.
5344 vector<Command*> cmds;
5345 playlist->rdiff (cmds);
5346 _session->add_commands (cmds);
5348 _session->add_command(new StatefulDiffCommand (playlist));
5354 progress->ascend ();
5362 commit_reversible_command ();
5366 Editor::external_edit_region ()
5372 Editor::reset_region_gain_envelopes ()
5374 RegionSelection rs = get_regions_from_selection_and_entered ();
5376 if (!_session || rs.empty()) {
5380 begin_reversible_command (_("reset region gain"));
5382 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5383 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5385 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5386 XMLNode& before (alist->get_state());
5388 arv->audio_region()->set_default_envelope ();
5389 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5393 commit_reversible_command ();
5397 Editor::set_region_gain_visibility (RegionView* rv)
5399 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5401 arv->update_envelope_visibility();
5406 Editor::set_gain_envelope_visibility ()
5412 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5413 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5415 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5421 Editor::toggle_gain_envelope_active ()
5423 if (_ignore_region_action) {
5427 RegionSelection rs = get_regions_from_selection_and_entered ();
5429 if (!_session || rs.empty()) {
5433 begin_reversible_command (_("region gain envelope active"));
5435 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5436 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5438 arv->region()->clear_changes ();
5439 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5440 _session->add_command (new StatefulDiffCommand (arv->region()));
5444 commit_reversible_command ();
5448 Editor::toggle_region_lock ()
5450 if (_ignore_region_action) {
5454 RegionSelection rs = get_regions_from_selection_and_entered ();
5456 if (!_session || rs.empty()) {
5460 begin_reversible_command (_("toggle region lock"));
5462 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5463 (*i)->region()->clear_changes ();
5464 (*i)->region()->set_locked (!(*i)->region()->locked());
5465 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5468 commit_reversible_command ();
5472 Editor::toggle_region_video_lock ()
5474 if (_ignore_region_action) {
5478 RegionSelection rs = get_regions_from_selection_and_entered ();
5480 if (!_session || rs.empty()) {
5484 begin_reversible_command (_("Toggle Video Lock"));
5486 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5487 (*i)->region()->clear_changes ();
5488 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5489 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5492 commit_reversible_command ();
5496 Editor::toggle_region_lock_style ()
5498 if (_ignore_region_action) {
5502 RegionSelection rs = get_regions_from_selection_and_entered ();
5504 if (!_session || rs.empty()) {
5508 begin_reversible_command (_("region lock style"));
5510 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5511 (*i)->region()->clear_changes ();
5512 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5513 (*i)->region()->set_position_lock_style (ns);
5514 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5517 commit_reversible_command ();
5521 Editor::toggle_opaque_region ()
5523 if (_ignore_region_action) {
5527 RegionSelection rs = get_regions_from_selection_and_entered ();
5529 if (!_session || rs.empty()) {
5533 begin_reversible_command (_("change region opacity"));
5535 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5536 (*i)->region()->clear_changes ();
5537 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5538 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5541 commit_reversible_command ();
5545 Editor::toggle_record_enable ()
5547 bool new_state = false;
5549 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5550 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5553 if (!rtav->is_track())
5557 new_state = !rtav->track()->record_enabled();
5561 rtav->track()->set_record_enabled (new_state, this);
5566 Editor::toggle_solo ()
5568 bool new_state = false;
5570 boost::shared_ptr<RouteList> rl (new RouteList);
5572 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5573 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5580 new_state = !rtav->route()->soloed ();
5584 rl->push_back (rtav->route());
5587 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5591 Editor::toggle_mute ()
5593 bool new_state = false;
5595 boost::shared_ptr<RouteList> rl (new RouteList);
5597 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5598 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5605 new_state = !rtav->route()->muted();
5609 rl->push_back (rtav->route());
5612 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5616 Editor::toggle_solo_isolate ()
5622 Editor::fade_range ()
5624 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5626 begin_reversible_command (_("fade range"));
5628 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5629 (*i)->fade_range (selection->time);
5632 commit_reversible_command ();
5637 Editor::set_fade_length (bool in)
5639 RegionSelection rs = get_regions_from_selection_and_entered ();
5645 /* we need a region to measure the offset from the start */
5647 RegionView* rv = rs.front ();
5649 framepos_t pos = get_preferred_edit_position();
5653 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5654 /* edit point is outside the relevant region */
5659 if (pos <= rv->region()->position()) {
5663 len = pos - rv->region()->position();
5664 cmd = _("set fade in length");
5666 if (pos >= rv->region()->last_frame()) {
5670 len = rv->region()->last_frame() - pos;
5671 cmd = _("set fade out length");
5674 begin_reversible_command (cmd);
5676 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5677 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5683 boost::shared_ptr<AutomationList> alist;
5685 alist = tmp->audio_region()->fade_in();
5687 alist = tmp->audio_region()->fade_out();
5690 XMLNode &before = alist->get_state();
5693 tmp->audio_region()->set_fade_in_length (len);
5694 tmp->audio_region()->set_fade_in_active (true);
5696 tmp->audio_region()->set_fade_out_length (len);
5697 tmp->audio_region()->set_fade_out_active (true);
5700 XMLNode &after = alist->get_state();
5701 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5704 commit_reversible_command ();
5708 Editor::set_fade_in_shape (FadeShape shape)
5710 RegionSelection rs = get_regions_from_selection_and_entered ();
5716 begin_reversible_command (_("set fade in shape"));
5718 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5719 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5725 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5726 XMLNode &before = alist->get_state();
5728 tmp->audio_region()->set_fade_in_shape (shape);
5730 XMLNode &after = alist->get_state();
5731 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5734 commit_reversible_command ();
5739 Editor::set_fade_out_shape (FadeShape shape)
5741 RegionSelection rs = get_regions_from_selection_and_entered ();
5747 begin_reversible_command (_("set fade out shape"));
5749 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5750 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5756 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5757 XMLNode &before = alist->get_state();
5759 tmp->audio_region()->set_fade_out_shape (shape);
5761 XMLNode &after = alist->get_state();
5762 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5765 commit_reversible_command ();
5769 Editor::set_fade_in_active (bool yn)
5771 RegionSelection rs = get_regions_from_selection_and_entered ();
5777 begin_reversible_command (_("set fade in active"));
5779 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5780 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5787 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5789 ar->clear_changes ();
5790 ar->set_fade_in_active (yn);
5791 _session->add_command (new StatefulDiffCommand (ar));
5794 commit_reversible_command ();
5798 Editor::set_fade_out_active (bool yn)
5800 RegionSelection rs = get_regions_from_selection_and_entered ();
5806 begin_reversible_command (_("set fade out active"));
5808 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5809 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5815 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5817 ar->clear_changes ();
5818 ar->set_fade_out_active (yn);
5819 _session->add_command(new StatefulDiffCommand (ar));
5822 commit_reversible_command ();
5826 Editor::toggle_region_fades (int dir)
5828 if (_ignore_region_action) {
5832 boost::shared_ptr<AudioRegion> ar;
5835 RegionSelection rs = get_regions_from_selection_and_entered ();
5841 RegionSelection::iterator i;
5842 for (i = rs.begin(); i != rs.end(); ++i) {
5843 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5845 yn = ar->fade_out_active ();
5847 yn = ar->fade_in_active ();
5853 if (i == rs.end()) {
5857 /* XXX should this undo-able? */
5859 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5860 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5863 if (dir == 1 || dir == 0) {
5864 ar->set_fade_in_active (!yn);
5867 if (dir == -1 || dir == 0) {
5868 ar->set_fade_out_active (!yn);
5874 /** Update region fade visibility after its configuration has been changed */
5876 Editor::update_region_fade_visibility ()
5878 bool _fade_visibility = _session->config.get_show_region_fades ();
5880 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5881 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5883 if (_fade_visibility) {
5884 v->audio_view()->show_all_fades ();
5886 v->audio_view()->hide_all_fades ();
5893 Editor::set_edit_point ()
5898 if (!mouse_frame (where, ignored)) {
5904 if (selection->markers.empty()) {
5906 mouse_add_new_marker (where);
5911 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5914 loc->move_to (where);
5920 Editor::set_playhead_cursor ()
5922 if (entered_marker) {
5923 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5928 if (!mouse_frame (where, ignored)) {
5935 _session->request_locate (where, _session->transport_rolling());
5939 if (ARDOUR_UI::config()->get_follow_edits()) {
5940 cancel_time_selection();
5945 Editor::split_region ()
5947 //if a range is selected, separate it
5948 if ( !selection->time.empty()) {
5949 separate_regions_between (selection->time);
5953 //if no range was selected, try to find some regions to split
5954 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
5956 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5958 framepos_t where = get_preferred_edit_position ();
5964 split_regions_at (where, rs);
5968 struct EditorOrderRouteSorter {
5969 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5970 return a->order_key () < b->order_key ();
5975 Editor::select_next_route()
5977 if (selection->tracks.empty()) {
5978 selection->set (track_views.front());
5982 TimeAxisView* current = selection->tracks.front();
5986 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5987 if (*i == current) {
5989 if (i != track_views.end()) {
5992 current = (*(track_views.begin()));
5993 //selection->set (*(track_views.begin()));
5998 rui = dynamic_cast<RouteUI *>(current);
5999 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6001 selection->set(current);
6003 ensure_time_axis_view_is_visible (*current, false);
6007 Editor::select_prev_route()
6009 if (selection->tracks.empty()) {
6010 selection->set (track_views.front());
6014 TimeAxisView* current = selection->tracks.front();
6018 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6019 if (*i == current) {
6021 if (i != track_views.rend()) {
6024 current = *(track_views.rbegin());
6029 rui = dynamic_cast<RouteUI *>(current);
6030 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6032 selection->set (current);
6034 ensure_time_axis_view_is_visible (*current, false);
6038 Editor::set_loop_from_selection (bool play)
6040 if (_session == 0) {
6044 framepos_t start, end;
6045 if (!get_selection_extents ( start, end))
6048 set_loop_range (start, end, _("set loop range from selection"));
6051 _session->request_play_loop (true, true);
6056 Editor::set_loop_from_region (bool play)
6058 framepos_t start, end;
6059 if (!get_selection_extents ( start, end))
6062 set_loop_range (start, end, _("set loop range from region"));
6065 _session->request_locate (start, true);
6066 _session->request_play_loop (true);
6071 Editor::set_punch_from_selection ()
6073 if (_session == 0) {
6077 framepos_t start, end;
6078 if (!get_selection_extents ( start, end))
6081 set_punch_range (start, end, _("set punch range from selection"));
6085 Editor::set_session_extents_from_selection ()
6087 if (_session == 0) {
6091 framepos_t start, end;
6092 if (!get_selection_extents ( start, end))
6096 if ((loc = _session->locations()->session_range_location()) == 0) {
6097 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6099 XMLNode &before = loc->get_state();
6101 _session->set_session_extents ( start, end );
6103 XMLNode &after = loc->get_state();
6105 begin_reversible_command (_("set session start/end from selection"));
6107 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6109 commit_reversible_command ();
6114 Editor::set_punch_from_region ()
6116 framepos_t start, end;
6117 if (!get_selection_extents ( start, end))
6120 set_punch_range (start, end, _("set punch range from region"));
6124 Editor::pitch_shift_region ()
6126 RegionSelection rs = get_regions_from_selection_and_entered ();
6128 RegionSelection audio_rs;
6129 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6130 if (dynamic_cast<AudioRegionView*> (*i)) {
6131 audio_rs.push_back (*i);
6135 if (audio_rs.empty()) {
6139 pitch_shift (audio_rs, 1.2);
6143 Editor::transpose_region ()
6145 RegionSelection rs = get_regions_from_selection_and_entered ();
6147 list<MidiRegionView*> midi_region_views;
6148 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6149 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6151 midi_region_views.push_back (mrv);
6156 int const r = d.run ();
6157 if (r != RESPONSE_ACCEPT) {
6161 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6162 (*i)->midi_region()->transpose (d.semitones ());
6167 Editor::set_tempo_from_region ()
6169 RegionSelection rs = get_regions_from_selection_and_entered ();
6171 if (!_session || rs.empty()) {
6175 RegionView* rv = rs.front();
6177 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6181 Editor::use_range_as_bar ()
6183 framepos_t start, end;
6184 if (get_edit_op_range (start, end)) {
6185 define_one_bar (start, end);
6190 Editor::define_one_bar (framepos_t start, framepos_t end)
6192 framepos_t length = end - start;
6194 const Meter& m (_session->tempo_map().meter_at (start));
6196 /* length = 1 bar */
6198 /* now we want frames per beat.
6199 we have frames per bar, and beats per bar, so ...
6202 /* XXXX METER MATH */
6204 double frames_per_beat = length / m.divisions_per_bar();
6206 /* beats per minute = */
6208 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6210 /* now decide whether to:
6212 (a) set global tempo
6213 (b) add a new tempo marker
6217 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6219 bool do_global = false;
6221 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6223 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6224 at the start, or create a new marker
6227 vector<string> options;
6228 options.push_back (_("Cancel"));
6229 options.push_back (_("Add new marker"));
6230 options.push_back (_("Set global tempo"));
6233 _("Define one bar"),
6234 _("Do you want to set the global tempo or add a new tempo marker?"),
6238 c.set_default_response (2);
6254 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6255 if the marker is at the region starter, change it, otherwise add
6260 begin_reversible_command (_("set tempo from region"));
6261 XMLNode& before (_session->tempo_map().get_state());
6264 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6265 } else if (t.frame() == start) {
6266 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6268 Timecode::BBT_Time bbt;
6269 _session->tempo_map().bbt_time (start, bbt);
6270 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6273 XMLNode& after (_session->tempo_map().get_state());
6275 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6276 commit_reversible_command ();
6280 Editor::split_region_at_transients ()
6282 AnalysisFeatureList positions;
6284 RegionSelection rs = get_regions_from_selection_and_entered ();
6286 if (!_session || rs.empty()) {
6290 begin_reversible_command (_("split regions"));
6292 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6294 RegionSelection::iterator tmp;
6299 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6301 if (ar && (ar->get_transients (positions) == 0)) {
6302 split_region_at_points ((*i)->region(), positions, true);
6309 commit_reversible_command ();
6314 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6316 bool use_rhythmic_rodent = false;
6318 boost::shared_ptr<Playlist> pl = r->playlist();
6320 list<boost::shared_ptr<Region> > new_regions;
6326 if (positions.empty()) {
6331 if (positions.size() > 20 && can_ferret) {
6332 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);
6333 MessageDialog msg (msgstr,
6336 Gtk::BUTTONS_OK_CANCEL);
6339 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6340 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6342 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6345 msg.set_title (_("Excessive split?"));
6348 int response = msg.run();
6354 case RESPONSE_APPLY:
6355 use_rhythmic_rodent = true;
6362 if (use_rhythmic_rodent) {
6363 show_rhythm_ferret ();
6367 AnalysisFeatureList::const_iterator x;
6369 pl->clear_changes ();
6370 pl->clear_owned_changes ();
6372 x = positions.begin();
6374 if (x == positions.end()) {
6379 pl->remove_region (r);
6383 while (x != positions.end()) {
6385 /* deal with positons that are out of scope of present region bounds */
6386 if (*x <= 0 || *x > r->length()) {
6391 /* file start = original start + how far we from the initial position ?
6394 framepos_t file_start = r->start() + pos;
6396 /* length = next position - current position
6399 framepos_t len = (*x) - pos;
6401 /* XXX we do we really want to allow even single-sample regions?
6402 shouldn't we have some kind of lower limit on region size?
6411 if (RegionFactory::region_name (new_name, r->name())) {
6415 /* do NOT announce new regions 1 by one, just wait till they are all done */
6419 plist.add (ARDOUR::Properties::start, file_start);
6420 plist.add (ARDOUR::Properties::length, len);
6421 plist.add (ARDOUR::Properties::name, new_name);
6422 plist.add (ARDOUR::Properties::layer, 0);
6424 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6425 /* because we set annouce to false, manually add the new region to the
6428 RegionFactory::map_add (nr);
6430 pl->add_region (nr, r->position() + pos);
6433 new_regions.push_front(nr);
6442 RegionFactory::region_name (new_name, r->name());
6444 /* Add the final region */
6447 plist.add (ARDOUR::Properties::start, r->start() + pos);
6448 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6449 plist.add (ARDOUR::Properties::name, new_name);
6450 plist.add (ARDOUR::Properties::layer, 0);
6452 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6453 /* because we set annouce to false, manually add the new region to the
6456 RegionFactory::map_add (nr);
6457 pl->add_region (nr, r->position() + pos);
6460 new_regions.push_front(nr);
6465 /* We might have removed regions, which alters other regions' layering_index,
6466 so we need to do a recursive diff here.
6468 vector<Command*> cmds;
6470 _session->add_commands (cmds);
6472 _session->add_command (new StatefulDiffCommand (pl));
6476 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6477 set_selected_regionview_from_region_list ((*i), Selection::Add);
6483 Editor::place_transient()
6489 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6495 framepos_t where = get_preferred_edit_position();
6497 begin_reversible_command (_("place transient"));
6499 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6500 framepos_t position = (*r)->region()->position();
6501 (*r)->region()->add_transient(where - position);
6504 commit_reversible_command ();
6508 Editor::remove_transient(ArdourCanvas::Item* item)
6514 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6517 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6518 _arv->remove_transient (*(float*) _line->get_data ("position"));
6522 Editor::snap_regions_to_grid ()
6524 list <boost::shared_ptr<Playlist > > used_playlists;
6526 RegionSelection rs = get_regions_from_selection_and_entered ();
6528 if (!_session || rs.empty()) {
6532 begin_reversible_command (_("snap regions to grid"));
6534 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6536 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6538 if (!pl->frozen()) {
6539 /* we haven't seen this playlist before */
6541 /* remember used playlists so we can thaw them later */
6542 used_playlists.push_back(pl);
6546 framepos_t start_frame = (*r)->region()->first_frame ();
6547 snap_to (start_frame);
6548 (*r)->region()->set_position (start_frame);
6551 while (used_playlists.size() > 0) {
6552 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6554 used_playlists.pop_front();
6557 commit_reversible_command ();
6561 Editor::close_region_gaps ()
6563 list <boost::shared_ptr<Playlist > > used_playlists;
6565 RegionSelection rs = get_regions_from_selection_and_entered ();
6567 if (!_session || rs.empty()) {
6571 Dialog dialog (_("Close Region Gaps"));
6574 table.set_spacings (12);
6575 table.set_border_width (12);
6576 Label* l = manage (left_aligned_label (_("Crossfade length")));
6577 table.attach (*l, 0, 1, 0, 1);
6579 SpinButton spin_crossfade (1, 0);
6580 spin_crossfade.set_range (0, 15);
6581 spin_crossfade.set_increments (1, 1);
6582 spin_crossfade.set_value (5);
6583 table.attach (spin_crossfade, 1, 2, 0, 1);
6585 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6587 l = manage (left_aligned_label (_("Pull-back length")));
6588 table.attach (*l, 0, 1, 1, 2);
6590 SpinButton spin_pullback (1, 0);
6591 spin_pullback.set_range (0, 100);
6592 spin_pullback.set_increments (1, 1);
6593 spin_pullback.set_value(30);
6594 table.attach (spin_pullback, 1, 2, 1, 2);
6596 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6598 dialog.get_vbox()->pack_start (table);
6599 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6600 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6603 if (dialog.run () == RESPONSE_CANCEL) {
6607 framepos_t crossfade_len = spin_crossfade.get_value();
6608 framepos_t pull_back_frames = spin_pullback.get_value();
6610 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6611 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6613 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6615 begin_reversible_command (_("close region gaps"));
6618 boost::shared_ptr<Region> last_region;
6620 rs.sort_by_position_and_track();
6622 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6624 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6626 if (!pl->frozen()) {
6627 /* we haven't seen this playlist before */
6629 /* remember used playlists so we can thaw them later */
6630 used_playlists.push_back(pl);
6634 framepos_t position = (*r)->region()->position();
6636 if (idx == 0 || position < last_region->position()){
6637 last_region = (*r)->region();
6642 (*r)->region()->trim_front( (position - pull_back_frames));
6643 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6645 last_region = (*r)->region();
6650 while (used_playlists.size() > 0) {
6651 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6653 used_playlists.pop_front();
6656 commit_reversible_command ();
6660 Editor::tab_to_transient (bool forward)
6662 AnalysisFeatureList positions;
6664 RegionSelection rs = get_regions_from_selection_and_entered ();
6670 framepos_t pos = _session->audible_frame ();
6672 if (!selection->tracks.empty()) {
6674 /* don't waste time searching for transients in duplicate playlists.
6677 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6679 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6681 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6684 boost::shared_ptr<Track> tr = rtv->track();
6686 boost::shared_ptr<Playlist> pl = tr->playlist ();
6688 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6691 positions.push_back (result);
6704 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6705 (*r)->region()->get_transients (positions);
6709 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6712 AnalysisFeatureList::iterator x;
6714 for (x = positions.begin(); x != positions.end(); ++x) {
6720 if (x != positions.end ()) {
6721 _session->request_locate (*x);
6725 AnalysisFeatureList::reverse_iterator x;
6727 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6733 if (x != positions.rend ()) {
6734 _session->request_locate (*x);
6740 Editor::playhead_forward_to_grid ()
6746 framepos_t pos = playhead_cursor->current_frame ();
6747 if (pos < max_framepos - 1) {
6749 snap_to_internal (pos, RoundUpAlways, false);
6750 _session->request_locate (pos);
6756 Editor::playhead_backward_to_grid ()
6762 framepos_t pos = playhead_cursor->current_frame ();
6765 snap_to_internal (pos, RoundDownAlways, false);
6766 _session->request_locate (pos);
6771 Editor::set_track_height (Height h)
6773 TrackSelection& ts (selection->tracks);
6775 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6776 (*x)->set_height_enum (h);
6781 Editor::toggle_tracks_active ()
6783 TrackSelection& ts (selection->tracks);
6785 bool target = false;
6791 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6792 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6796 target = !rtv->_route->active();
6799 rtv->_route->set_active (target, this);
6805 Editor::remove_tracks ()
6807 /* this will delete GUI objects that may be the subject of an event
6808 handler in which this method is called. Defer actual deletion to the
6809 next idle callback, when all event handling is finished.
6811 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
6815 Editor::idle_remove_tracks ()
6818 return false; /* do not call again */
6822 Editor::_remove_tracks ()
6824 TrackSelection& ts (selection->tracks);
6830 vector<string> choices;
6834 const char* trackstr;
6836 vector<boost::shared_ptr<Route> > routes;
6837 bool special_bus = false;
6839 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6840 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6844 if (rtv->is_track()) {
6849 routes.push_back (rtv->_route);
6851 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6856 if (special_bus && !Config->get_allow_special_bus_removal()) {
6857 MessageDialog msg (_("That would be bad news ...."),
6861 msg.set_secondary_text (string_compose (_(
6862 "Removing the master or monitor bus is such a bad idea\n\
6863 that %1 is not going to allow it.\n\
6865 If you really want to do this sort of thing\n\
6866 edit your ardour.rc file to set the\n\
6867 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6874 if (ntracks + nbusses == 0) {
6878 trackstr = P_("track", "tracks", ntracks);
6879 busstr = P_("bus", "busses", nbusses);
6883 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6884 "(You may also lose the playlists associated with the %2)\n\n"
6885 "This action cannot be undone, and the session file will be overwritten!"),
6886 ntracks, trackstr, nbusses, busstr);
6888 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6889 "(You may also lose the playlists associated with the %2)\n\n"
6890 "This action cannot be undone, and the session file will be overwritten!"),
6893 } else if (nbusses) {
6894 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6895 "This action cannot be undone, and the session file will be overwritten"),
6899 choices.push_back (_("No, do nothing."));
6900 if (ntracks + nbusses > 1) {
6901 choices.push_back (_("Yes, remove them."));
6903 choices.push_back (_("Yes, remove it."));
6908 title = string_compose (_("Remove %1"), trackstr);
6910 title = string_compose (_("Remove %1"), busstr);
6913 Choice prompter (title, prompt, choices);
6915 if (prompter.run () != 1) {
6920 Session::StateProtector sp (_session);
6921 DisplaySuspender ds;
6922 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6923 _session->remove_route (*x);
6929 Editor::do_insert_time ()
6931 if (selection->tracks.empty()) {
6935 InsertRemoveTimeDialog d (*this);
6936 int response = d.run ();
6938 if (response != RESPONSE_OK) {
6942 if (d.distance() == 0) {
6946 InsertTimeOption opt = d.intersected_region_action ();
6949 get_preferred_edit_position(),
6955 d.move_glued_markers(),
6956 d.move_locked_markers(),
6962 Editor::insert_time (
6963 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6964 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6967 bool commit = false;
6969 if (Config->get_edit_mode() == Lock) {
6973 begin_reversible_command (_("insert time"));
6975 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6977 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6981 /* don't operate on any playlist more than once, which could
6982 * happen if "all playlists" is enabled, but there is more
6983 * than 1 track using playlists "from" a given track.
6986 set<boost::shared_ptr<Playlist> > pl;
6988 if (all_playlists) {
6989 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6991 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6992 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6997 if ((*x)->playlist ()) {
6998 pl.insert ((*x)->playlist ());
7002 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7004 (*i)->clear_changes ();
7005 (*i)->clear_owned_changes ();
7007 if (opt == SplitIntersected) {
7011 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7013 vector<Command*> cmds;
7015 _session->add_commands (cmds);
7017 _session->add_command (new StatefulDiffCommand (*i));
7022 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7024 rtav->route ()->shift (pos, frames);
7032 XMLNode& before (_session->locations()->get_state());
7033 Locations::LocationList copy (_session->locations()->list());
7035 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7037 Locations::LocationList::const_iterator tmp;
7039 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7040 bool const was_locked = (*i)->locked ();
7041 if (locked_markers_too) {
7045 if ((*i)->start() >= pos) {
7046 // move end first, in case we're moving by more than the length of the range
7047 if (!(*i)->is_mark()) {
7048 (*i)->set_end ((*i)->end() + frames);
7050 (*i)->set_start ((*i)->start() + frames);
7061 XMLNode& after (_session->locations()->get_state());
7062 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7067 _session->tempo_map().insert_time (pos, frames);
7071 commit_reversible_command ();
7076 Editor::do_remove_time ()
7078 if (selection->tracks.empty()) {
7082 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7083 InsertRemoveTimeDialog d (*this, true);
7085 int response = d.run ();
7087 if (response != RESPONSE_OK) {
7091 framecnt_t distance = d.distance();
7093 if (distance == 0) {
7103 d.move_glued_markers(),
7104 d.move_locked_markers(),
7110 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7111 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7113 bool commit = false;
7115 if (Config->get_edit_mode() == Lock) {
7116 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7120 begin_reversible_command (_("cut time"));
7122 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7124 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7128 XMLNode &before = pl->get_state();
7130 std::list<AudioRange> rl;
7131 AudioRange ar(pos, pos+frames, 0);
7134 pl->shift (pos, -frames, true, ignore_music_glue);
7136 XMLNode &after = pl->get_state();
7138 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7143 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7145 rtav->route ()->shift (pos, -frames);
7150 std::list<Location*> loc_kill_list;
7155 XMLNode& before (_session->locations()->get_state());
7156 Locations::LocationList copy (_session->locations()->list());
7158 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7159 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7161 bool const was_locked = (*i)->locked ();
7162 if (locked_markers_too) {
7166 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7167 if ((*i)->end() >= pos
7168 && (*i)->end() < pos+frames
7169 && (*i)->start() >= pos
7170 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7172 loc_kill_list.push_back(*i);
7173 } else { // only start or end is included, try to do the right thing
7174 // move start before moving end, to avoid trying to move the end to before the start
7175 // if we're removing more time than the length of the range
7176 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7177 // start is within cut
7178 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7180 } else if ((*i)->start() >= pos+frames) {
7181 // start (and thus entire range) lies beyond end of cut
7182 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7185 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7186 // end is inside cut
7187 (*i)->set_end (pos); // bring the end to the cut
7189 } else if ((*i)->end() >= pos+frames) {
7190 // end is beyond end of cut
7191 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7196 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7197 loc_kill_list.push_back(*i);
7199 } else if ((*i)->start() >= pos) {
7200 (*i)->set_start ((*i)->start() -frames);
7210 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7211 _session->locations()->remove( *i );
7215 XMLNode& after (_session->locations()->get_state());
7216 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7222 XMLNode& before (_session->tempo_map().get_state());
7224 if (_session->tempo_map().remove_time (pos, frames) ) {
7225 XMLNode& after (_session->tempo_map().get_state());
7226 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7232 commit_reversible_command ();
7237 Editor::fit_selection ()
7239 if (!selection->tracks.empty()) {
7240 fit_tracks (selection->tracks);
7244 /* no selected tracks - use tracks with selected regions */
7246 if (!selection->regions.empty()) {
7247 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7248 tvl.push_back (&(*r)->get_time_axis_view ());
7254 } else if (internal_editing()) {
7255 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7258 if (entered_track) {
7259 tvl.push_back (entered_track);
7268 Editor::fit_tracks (TrackViewList & tracks)
7270 if (tracks.empty()) {
7274 uint32_t child_heights = 0;
7275 int visible_tracks = 0;
7277 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7279 if (!(*t)->marked_for_display()) {
7283 child_heights += (*t)->effective_height() - (*t)->current_height();
7287 /* compute the per-track height from:
7289 total canvas visible height -
7290 height that will be taken by visible children of selected
7291 tracks - height of the ruler/hscroll area
7293 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7294 double first_y_pos = DBL_MAX;
7296 if (h < TimeAxisView::preset_height (HeightSmall)) {
7297 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7298 /* too small to be displayed */
7302 undo_visual_stack.push_back (current_visual_state (true));
7303 PBD::Unwinder<bool> nsv (no_save_visual, true);
7305 /* build a list of all tracks, including children */
7308 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7310 TimeAxisView::Children c = (*i)->get_child_list ();
7311 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7312 all.push_back (j->get());
7317 // find selection range.
7318 // if someone knows how to user TrackViewList::iterator for this
7320 int selected_top = -1;
7321 int selected_bottom = -1;
7323 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7324 if ((*t)->marked_for_display ()) {
7325 if (tracks.contains(*t)) {
7326 if (selected_top == -1) {
7329 selected_bottom = i;
7335 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7336 if ((*t)->marked_for_display ()) {
7337 if (tracks.contains(*t)) {
7338 (*t)->set_height (h);
7339 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7341 if (i > selected_top && i < selected_bottom) {
7342 hide_track_in_display (*t);
7349 set the controls_layout height now, because waiting for its size
7350 request signal handler will cause the vertical adjustment setting to fail
7353 controls_layout.property_height () = _full_canvas_height;
7354 vertical_adjustment.set_value (first_y_pos);
7356 redo_visual_stack.push_back (current_visual_state (true));
7358 visible_tracks_selector.set_text (_("Sel"));
7362 Editor::save_visual_state (uint32_t n)
7364 while (visual_states.size() <= n) {
7365 visual_states.push_back (0);
7368 if (visual_states[n] != 0) {
7369 delete visual_states[n];
7372 visual_states[n] = current_visual_state (true);
7377 Editor::goto_visual_state (uint32_t n)
7379 if (visual_states.size() <= n) {
7383 if (visual_states[n] == 0) {
7387 use_visual_state (*visual_states[n]);
7391 Editor::start_visual_state_op (uint32_t n)
7393 save_visual_state (n);
7395 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7397 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7398 pup->set_text (buf);
7403 Editor::cancel_visual_state_op (uint32_t n)
7405 goto_visual_state (n);
7409 Editor::toggle_region_mute ()
7411 if (_ignore_region_action) {
7415 RegionSelection rs = get_regions_from_selection_and_entered ();
7421 if (rs.size() > 1) {
7422 begin_reversible_command (_("mute regions"));
7424 begin_reversible_command (_("mute region"));
7427 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7429 (*i)->region()->playlist()->clear_changes ();
7430 (*i)->region()->set_muted (!(*i)->region()->muted ());
7431 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7435 commit_reversible_command ();
7439 Editor::combine_regions ()
7441 /* foreach track with selected regions, take all selected regions
7442 and join them into a new region containing the subregions (as a
7446 typedef set<RouteTimeAxisView*> RTVS;
7449 if (selection->regions.empty()) {
7453 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7454 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7457 tracks.insert (rtv);
7461 begin_reversible_command (_("combine regions"));
7463 vector<RegionView*> new_selection;
7465 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7468 if ((rv = (*i)->combine_regions ()) != 0) {
7469 new_selection.push_back (rv);
7473 selection->clear_regions ();
7474 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7475 selection->add (*i);
7478 commit_reversible_command ();
7482 Editor::uncombine_regions ()
7484 typedef set<RouteTimeAxisView*> RTVS;
7487 if (selection->regions.empty()) {
7491 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7492 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7495 tracks.insert (rtv);
7499 begin_reversible_command (_("uncombine regions"));
7501 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7502 (*i)->uncombine_regions ();
7505 commit_reversible_command ();
7509 Editor::toggle_midi_input_active (bool flip_others)
7512 boost::shared_ptr<RouteList> rl (new RouteList);
7514 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7515 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7521 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7524 rl->push_back (rtav->route());
7525 onoff = !mt->input_active();
7529 _session->set_exclusive_input_active (rl, onoff, flip_others);
7536 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7538 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7539 lock_dialog->get_vbox()->pack_start (*padlock);
7541 ArdourButton* b = manage (new ArdourButton);
7542 b->set_name ("lock button");
7543 b->set_text (_("Click to unlock"));
7544 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7545 lock_dialog->get_vbox()->pack_start (*b);
7547 lock_dialog->get_vbox()->show_all ();
7548 lock_dialog->set_size_request (200, 200);
7552 /* The global menu bar continues to be accessible to applications
7553 with modal dialogs, which means that we need to desensitize
7554 all items in the menu bar. Since those items are really just
7555 proxies for actions, that means disabling all actions.
7557 ActionManager::disable_all_actions ();
7559 lock_dialog->present ();
7565 lock_dialog->hide ();
7568 ActionManager::pop_action_state ();
7571 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7572 start_lock_event_timing ();
7577 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7579 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7583 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7585 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7586 Gtkmm2ext::UI::instance()->flush_pending ();
7590 Editor::bring_all_sources_into_session ()
7597 ArdourDialog w (_("Moving embedded files into session folder"));
7598 w.get_vbox()->pack_start (msg);
7601 /* flush all pending GUI events because we're about to start copying
7605 Gtkmm2ext::UI::instance()->flush_pending ();
7609 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));