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_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::add_location_from_playhead_cursor ()
2120 add_location_mark (_session->audible_frame());
2124 Editor::remove_location_at_playhead_cursor ()
2129 begin_reversible_command (_("remove marker"));
2131 XMLNode &before = _session->locations()->get_state();
2132 bool removed = false;
2134 //find location(s) at this time
2135 Locations::LocationList locs;
2136 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2137 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2138 if ((*i)->is_mark()) {
2139 _session->locations()->remove (*i);
2146 XMLNode &after = _session->locations()->get_state();
2147 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2149 commit_reversible_command ();
2154 /** Add a range marker around each selected region */
2156 Editor::add_locations_from_region ()
2158 RegionSelection rs = get_regions_from_selection_and_entered ();
2164 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2166 XMLNode &before = _session->locations()->get_state();
2168 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2170 boost::shared_ptr<Region> region = (*i)->region ();
2172 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2174 _session->locations()->add (location, true);
2177 XMLNode &after = _session->locations()->get_state();
2178 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2180 commit_reversible_command ();
2183 /** Add a single range marker around all selected regions */
2185 Editor::add_location_from_region ()
2187 RegionSelection rs = get_regions_from_selection_and_entered ();
2193 begin_reversible_command (_("add marker"));
2195 XMLNode &before = _session->locations()->get_state();
2199 if (rs.size() > 1) {
2200 _session->locations()->next_available_name(markername, "regions");
2202 RegionView* rv = *(rs.begin());
2203 boost::shared_ptr<Region> region = rv->region();
2204 markername = region->name();
2207 if (!choose_new_marker_name(markername)) {
2211 // single range spanning all selected
2212 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2213 _session->locations()->add (location, true);
2215 XMLNode &after = _session->locations()->get_state();
2216 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2218 commit_reversible_command ();
2224 Editor::jump_forward_to_mark ()
2230 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2236 _session->request_locate (pos, _session->transport_rolling());
2240 Editor::jump_backward_to_mark ()
2246 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2252 _session->request_locate (pos, _session->transport_rolling());
2258 framepos_t const pos = _session->audible_frame ();
2261 _session->locations()->next_available_name (markername, "mark");
2263 if (!choose_new_marker_name (markername)) {
2267 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2271 Editor::clear_markers ()
2274 begin_reversible_command (_("clear markers"));
2276 XMLNode &before = _session->locations()->get_state();
2277 _session->locations()->clear_markers ();
2278 XMLNode &after = _session->locations()->get_state();
2279 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2281 commit_reversible_command ();
2286 Editor::clear_ranges ()
2289 begin_reversible_command (_("clear ranges"));
2291 XMLNode &before = _session->locations()->get_state();
2293 _session->locations()->clear_ranges ();
2295 XMLNode &after = _session->locations()->get_state();
2296 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2298 commit_reversible_command ();
2303 Editor::clear_locations ()
2305 begin_reversible_command (_("clear locations"));
2307 XMLNode &before = _session->locations()->get_state();
2308 _session->locations()->clear ();
2309 XMLNode &after = _session->locations()->get_state();
2310 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2312 commit_reversible_command ();
2316 Editor::unhide_markers ()
2318 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2319 Location *l = (*i).first;
2320 if (l->is_hidden() && l->is_mark()) {
2321 l->set_hidden(false, this);
2327 Editor::unhide_ranges ()
2329 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2330 Location *l = (*i).first;
2331 if (l->is_hidden() && l->is_range_marker()) {
2332 l->set_hidden(false, this);
2337 /* INSERT/REPLACE */
2340 Editor::insert_region_list_selection (float times)
2342 RouteTimeAxisView *tv = 0;
2343 boost::shared_ptr<Playlist> playlist;
2345 if (clicked_routeview != 0) {
2346 tv = clicked_routeview;
2347 } else if (!selection->tracks.empty()) {
2348 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2351 } else if (entered_track != 0) {
2352 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2359 if ((playlist = tv->playlist()) == 0) {
2363 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2368 begin_reversible_command (_("insert region"));
2369 playlist->clear_changes ();
2370 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2371 if (Config->get_edit_mode() == Ripple)
2372 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2374 _session->add_command(new StatefulDiffCommand (playlist));
2375 commit_reversible_command ();
2378 /* BUILT-IN EFFECTS */
2381 Editor::reverse_selection ()
2386 /* GAIN ENVELOPE EDITING */
2389 Editor::edit_envelope ()
2396 Editor::transition_to_rolling (bool fwd)
2402 if (_session->config.get_external_sync()) {
2403 switch (Config->get_sync_source()) {
2407 /* transport controlled by the master */
2412 if (_session->is_auditioning()) {
2413 _session->cancel_audition ();
2417 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2421 Editor::play_from_start ()
2423 _session->request_locate (_session->current_start_frame(), true);
2427 Editor::play_from_edit_point ()
2429 _session->request_locate (get_preferred_edit_position(), true);
2433 Editor::play_from_edit_point_and_return ()
2435 framepos_t start_frame;
2436 framepos_t return_frame;
2438 start_frame = get_preferred_edit_position (true);
2440 if (_session->transport_rolling()) {
2441 _session->request_locate (start_frame, false);
2445 /* don't reset the return frame if its already set */
2447 if ((return_frame = _session->requested_return_frame()) < 0) {
2448 return_frame = _session->audible_frame();
2451 if (start_frame >= 0) {
2452 _session->request_roll_at_and_return (start_frame, return_frame);
2457 Editor::play_selection ()
2459 framepos_t start, end;
2460 if (!get_selection_extents ( start, end))
2463 AudioRange ar (start, end, 0);
2464 list<AudioRange> lar;
2467 _session->request_play_range (&lar, true);
2471 Editor::get_preroll ()
2473 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2478 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2480 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2483 location -= get_preroll();
2485 //don't try to locate before the beginning of time
2489 //if follow_playhead is on, keep the playhead on the screen
2490 if ( _follow_playhead )
2491 if ( location < leftmost_frame )
2492 location = leftmost_frame;
2494 _session->request_locate( location );
2498 Editor::play_with_preroll ()
2501 framepos_t preroll = get_preroll();
2503 framepos_t start, end;
2504 if (!get_selection_extents ( start, end))
2507 if (start > preroll)
2508 start = start - preroll;
2510 end = end + preroll; //"post-roll"
2512 AudioRange ar (start, end, 0);
2513 list<AudioRange> lar;
2516 _session->request_play_range (&lar, true);
2521 Editor::play_location (Location& location)
2523 if (location.start() <= location.end()) {
2527 _session->request_bounded_roll (location.start(), location.end());
2531 Editor::loop_location (Location& location)
2533 if (location.start() <= location.end()) {
2539 if ((tll = transport_loop_location()) != 0) {
2540 tll->set (location.start(), location.end());
2542 // enable looping, reposition and start rolling
2543 _session->request_locate (tll->start(), true);
2544 _session->request_play_loop (true);
2549 Editor::do_layer_operation (LayerOperation op)
2551 if (selection->regions.empty ()) {
2555 bool const multiple = selection->regions.size() > 1;
2559 begin_reversible_command (_("raise regions"));
2561 begin_reversible_command (_("raise region"));
2567 begin_reversible_command (_("raise regions to top"));
2569 begin_reversible_command (_("raise region to top"));
2575 begin_reversible_command (_("lower regions"));
2577 begin_reversible_command (_("lower region"));
2583 begin_reversible_command (_("lower regions to bottom"));
2585 begin_reversible_command (_("lower region"));
2590 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2591 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2592 (*i)->clear_owned_changes ();
2595 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2596 boost::shared_ptr<Region> r = (*i)->region ();
2608 r->lower_to_bottom ();
2612 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2613 vector<Command*> cmds;
2615 _session->add_commands (cmds);
2618 commit_reversible_command ();
2622 Editor::raise_region ()
2624 do_layer_operation (Raise);
2628 Editor::raise_region_to_top ()
2630 do_layer_operation (RaiseToTop);
2634 Editor::lower_region ()
2636 do_layer_operation (Lower);
2640 Editor::lower_region_to_bottom ()
2642 do_layer_operation (LowerToBottom);
2645 /** Show the region editor for the selected regions */
2647 Editor::show_region_properties ()
2649 selection->foreach_regionview (&RegionView::show_region_editor);
2652 /** Show the midi list editor for the selected MIDI regions */
2654 Editor::show_midi_list_editor ()
2656 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2660 Editor::rename_region ()
2662 RegionSelection rs = get_regions_from_selection_and_entered ();
2668 ArdourDialog d (*this, _("Rename Region"), true, false);
2670 Label label (_("New name:"));
2673 hbox.set_spacing (6);
2674 hbox.pack_start (label, false, false);
2675 hbox.pack_start (entry, true, true);
2677 d.get_vbox()->set_border_width (12);
2678 d.get_vbox()->pack_start (hbox, false, false);
2680 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2681 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2683 d.set_size_request (300, -1);
2685 entry.set_text (rs.front()->region()->name());
2686 entry.select_region (0, -1);
2688 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2694 int const ret = d.run();
2698 if (ret != RESPONSE_OK) {
2702 std::string str = entry.get_text();
2703 strip_whitespace_edges (str);
2705 rs.front()->region()->set_name (str);
2706 _regions->redisplay ();
2711 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2713 if (_session->is_auditioning()) {
2714 _session->cancel_audition ();
2717 // note: some potential for creativity here, because region doesn't
2718 // have to belong to the playlist that Route is handling
2720 // bool was_soloed = route.soloed();
2722 route.set_solo (true, this);
2724 _session->request_bounded_roll (region->position(), region->position() + region->length());
2726 /* XXX how to unset the solo state ? */
2729 /** Start an audition of the first selected region */
2731 Editor::play_edit_range ()
2733 framepos_t start, end;
2735 if (get_edit_op_range (start, end)) {
2736 _session->request_bounded_roll (start, end);
2741 Editor::play_selected_region ()
2743 framepos_t start = max_framepos;
2746 RegionSelection rs = get_regions_from_selection_and_entered ();
2752 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2753 if ((*i)->region()->position() < start) {
2754 start = (*i)->region()->position();
2756 if ((*i)->region()->last_frame() + 1 > end) {
2757 end = (*i)->region()->last_frame() + 1;
2761 _session->request_bounded_roll (start, end);
2765 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2767 _session->audition_region (region);
2771 Editor::region_from_selection ()
2773 if (clicked_axisview == 0) {
2777 if (selection->time.empty()) {
2781 framepos_t start = selection->time[clicked_selection].start;
2782 framepos_t end = selection->time[clicked_selection].end;
2784 TrackViewList tracks = get_tracks_for_range_action ();
2786 framepos_t selection_cnt = end - start + 1;
2788 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2789 boost::shared_ptr<Region> current;
2790 boost::shared_ptr<Playlist> pl;
2791 framepos_t internal_start;
2794 if ((pl = (*i)->playlist()) == 0) {
2798 if ((current = pl->top_region_at (start)) == 0) {
2802 internal_start = start - current->position();
2803 RegionFactory::region_name (new_name, current->name(), true);
2807 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2808 plist.add (ARDOUR::Properties::length, selection_cnt);
2809 plist.add (ARDOUR::Properties::name, new_name);
2810 plist.add (ARDOUR::Properties::layer, 0);
2812 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2817 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2819 if (selection->time.empty() || selection->tracks.empty()) {
2823 framepos_t start, end;
2824 if (clicked_selection) {
2825 start = selection->time[clicked_selection].start;
2826 end = selection->time[clicked_selection].end;
2828 start = selection->time.start();
2829 end = selection->time.end_frame();
2832 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2833 sort_track_selection (ts);
2835 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2836 boost::shared_ptr<Region> current;
2837 boost::shared_ptr<Playlist> playlist;
2838 framepos_t internal_start;
2841 if ((playlist = (*i)->playlist()) == 0) {
2845 if ((current = playlist->top_region_at(start)) == 0) {
2849 internal_start = start - current->position();
2850 RegionFactory::region_name (new_name, current->name(), true);
2854 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2855 plist.add (ARDOUR::Properties::length, end - start + 1);
2856 plist.add (ARDOUR::Properties::name, new_name);
2858 new_regions.push_back (RegionFactory::create (current, plist));
2863 Editor::split_multichannel_region ()
2865 RegionSelection rs = get_regions_from_selection_and_entered ();
2871 vector< boost::shared_ptr<Region> > v;
2873 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2874 (*x)->region()->separate_by_channel (*_session, v);
2879 Editor::new_region_from_selection ()
2881 region_from_selection ();
2882 cancel_selection ();
2886 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2888 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2889 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2890 case Evoral::OverlapNone:
2898 * - selected tracks, or if there are none...
2899 * - tracks containing selected regions, or if there are none...
2904 Editor::get_tracks_for_range_action () const
2908 if (selection->tracks.empty()) {
2910 /* use tracks with selected regions */
2912 RegionSelection rs = selection->regions;
2914 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2915 TimeAxisView* tv = &(*i)->get_time_axis_view();
2917 if (!t.contains (tv)) {
2923 /* no regions and no tracks: use all tracks */
2929 t = selection->tracks;
2932 return t.filter_to_unique_playlists();
2936 Editor::separate_regions_between (const TimeSelection& ts)
2938 bool in_command = false;
2939 boost::shared_ptr<Playlist> playlist;
2940 RegionSelection new_selection;
2942 TrackViewList tmptracks = get_tracks_for_range_action ();
2943 sort_track_selection (tmptracks);
2945 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2947 RouteTimeAxisView* rtv;
2949 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2951 if (rtv->is_track()) {
2953 /* no edits to destructive tracks */
2955 if (rtv->track()->destructive()) {
2959 if ((playlist = rtv->playlist()) != 0) {
2961 playlist->clear_changes ();
2963 /* XXX need to consider musical time selections here at some point */
2965 double speed = rtv->track()->speed();
2968 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2970 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2971 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2973 latest_regionviews.clear ();
2975 playlist->partition ((framepos_t)((*t).start * speed),
2976 (framepos_t)((*t).end * speed), false);
2980 if (!latest_regionviews.empty()) {
2982 rtv->view()->foreach_regionview (sigc::bind (
2983 sigc::ptr_fun (add_if_covered),
2984 &(*t), &new_selection));
2987 begin_reversible_command (_("separate"));
2991 /* pick up changes to existing regions */
2993 vector<Command*> cmds;
2994 playlist->rdiff (cmds);
2995 _session->add_commands (cmds);
2997 /* pick up changes to the playlist itself (adds/removes)
3000 _session->add_command(new StatefulDiffCommand (playlist));
3009 // selection->set (new_selection);
3011 commit_reversible_command ();
3015 struct PlaylistState {
3016 boost::shared_ptr<Playlist> playlist;
3020 /** Take tracks from get_tracks_for_range_action and cut any regions
3021 * on those tracks so that the tracks are empty over the time
3025 Editor::separate_region_from_selection ()
3027 /* preferentially use *all* ranges in the time selection if we're in range mode
3028 to allow discontiguous operation, since get_edit_op_range() currently
3029 returns a single range.
3032 if (!selection->time.empty()) {
3034 separate_regions_between (selection->time);
3041 if (get_edit_op_range (start, end)) {
3043 AudioRange ar (start, end, 1);
3047 separate_regions_between (ts);
3053 Editor::separate_region_from_punch ()
3055 Location* loc = _session->locations()->auto_punch_location();
3057 separate_regions_using_location (*loc);
3062 Editor::separate_region_from_loop ()
3064 Location* loc = _session->locations()->auto_loop_location();
3066 separate_regions_using_location (*loc);
3071 Editor::separate_regions_using_location (Location& loc)
3073 if (loc.is_mark()) {
3077 AudioRange ar (loc.start(), loc.end(), 1);
3082 separate_regions_between (ts);
3085 /** Separate regions under the selected region */
3087 Editor::separate_under_selected_regions ()
3089 vector<PlaylistState> playlists;
3093 rs = get_regions_from_selection_and_entered();
3095 if (!_session || rs.empty()) {
3099 begin_reversible_command (_("separate region under"));
3101 list<boost::shared_ptr<Region> > regions_to_remove;
3103 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3104 // we can't just remove the region(s) in this loop because
3105 // this removes them from the RegionSelection, and they thus
3106 // disappear from underneath the iterator, and the ++i above
3107 // SEGVs in a puzzling fashion.
3109 // so, first iterate over the regions to be removed from rs and
3110 // add them to the regions_to_remove list, and then
3111 // iterate over the list to actually remove them.
3113 regions_to_remove.push_back ((*i)->region());
3116 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3118 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3121 // is this check necessary?
3125 vector<PlaylistState>::iterator i;
3127 //only take state if this is a new playlist.
3128 for (i = playlists.begin(); i != playlists.end(); ++i) {
3129 if ((*i).playlist == playlist) {
3134 if (i == playlists.end()) {
3136 PlaylistState before;
3137 before.playlist = playlist;
3138 before.before = &playlist->get_state();
3140 playlist->freeze ();
3141 playlists.push_back(before);
3144 //Partition on the region bounds
3145 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3147 //Re-add region that was just removed due to the partition operation
3148 playlist->add_region( (*rl), (*rl)->first_frame() );
3151 vector<PlaylistState>::iterator pl;
3153 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3154 (*pl).playlist->thaw ();
3155 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3158 commit_reversible_command ();
3162 Editor::crop_region_to_selection ()
3164 if (!selection->time.empty()) {
3166 crop_region_to (selection->time.start(), selection->time.end_frame());
3173 if (get_edit_op_range (start, end)) {
3174 crop_region_to (start, end);
3181 Editor::crop_region_to (framepos_t start, framepos_t end)
3183 vector<boost::shared_ptr<Playlist> > playlists;
3184 boost::shared_ptr<Playlist> playlist;
3187 if (selection->tracks.empty()) {
3188 ts = track_views.filter_to_unique_playlists();
3190 ts = selection->tracks.filter_to_unique_playlists ();
3193 sort_track_selection (ts);
3195 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3197 RouteTimeAxisView* rtv;
3199 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3201 boost::shared_ptr<Track> t = rtv->track();
3203 if (t != 0 && ! t->destructive()) {
3205 if ((playlist = rtv->playlist()) != 0) {
3206 playlists.push_back (playlist);
3212 if (playlists.empty()) {
3216 framepos_t the_start;
3220 begin_reversible_command (_("trim to selection"));
3222 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3224 boost::shared_ptr<Region> region;
3228 if ((region = (*i)->top_region_at(the_start)) == 0) {
3232 /* now adjust lengths to that we do the right thing
3233 if the selection extends beyond the region
3236 the_start = max (the_start, (framepos_t) region->position());
3237 if (max_framepos - the_start < region->length()) {
3238 the_end = the_start + region->length() - 1;
3240 the_end = max_framepos;
3242 the_end = min (end, the_end);
3243 cnt = the_end - the_start + 1;
3245 region->clear_changes ();
3246 region->trim_to (the_start, cnt);
3247 _session->add_command (new StatefulDiffCommand (region));
3250 commit_reversible_command ();
3254 Editor::region_fill_track ()
3256 RegionSelection rs = get_regions_from_selection_and_entered ();
3258 if (!_session || rs.empty()) {
3262 framepos_t const end = _session->current_end_frame ();
3264 begin_reversible_command (Operations::region_fill);
3266 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3268 boost::shared_ptr<Region> region ((*i)->region());
3270 boost::shared_ptr<Playlist> pl = region->playlist();
3272 if (end <= region->last_frame()) {
3276 double times = (double) (end - region->last_frame()) / (double) region->length();
3282 pl->clear_changes ();
3283 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3284 _session->add_command (new StatefulDiffCommand (pl));
3287 commit_reversible_command ();
3291 Editor::region_fill_selection ()
3293 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3297 if (selection->time.empty()) {
3301 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3306 framepos_t start = selection->time[clicked_selection].start;
3307 framepos_t end = selection->time[clicked_selection].end;
3309 boost::shared_ptr<Playlist> playlist;
3311 if (selection->tracks.empty()) {
3315 framepos_t selection_length = end - start;
3316 float times = (float)selection_length / region->length();
3318 begin_reversible_command (Operations::fill_selection);
3320 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3322 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3324 if ((playlist = (*i)->playlist()) == 0) {
3328 playlist->clear_changes ();
3329 playlist->add_region (RegionFactory::create (region, true), start, times);
3330 _session->add_command (new StatefulDiffCommand (playlist));
3333 commit_reversible_command ();
3337 Editor::set_region_sync_position ()
3339 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3343 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3345 bool in_command = false;
3347 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3349 if (!(*r)->region()->covers (where)) {
3353 boost::shared_ptr<Region> region ((*r)->region());
3356 begin_reversible_command (_("set sync point"));
3360 region->clear_changes ();
3361 region->set_sync_position (where);
3362 _session->add_command(new StatefulDiffCommand (region));
3366 commit_reversible_command ();
3370 /** Remove the sync positions of the selection */
3372 Editor::remove_region_sync ()
3374 RegionSelection rs = get_regions_from_selection_and_entered ();
3380 begin_reversible_command (_("remove region sync"));
3382 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3384 (*i)->region()->clear_changes ();
3385 (*i)->region()->clear_sync_position ();
3386 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3389 commit_reversible_command ();
3393 Editor::naturalize_region ()
3395 RegionSelection rs = get_regions_from_selection_and_entered ();
3401 if (rs.size() > 1) {
3402 begin_reversible_command (_("move regions to original position"));
3404 begin_reversible_command (_("move region to original position"));
3407 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3408 (*i)->region()->clear_changes ();
3409 (*i)->region()->move_to_natural_position ();
3410 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3413 commit_reversible_command ();
3417 Editor::align_regions (RegionPoint what)
3419 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3425 begin_reversible_command (_("align selection"));
3427 framepos_t const position = get_preferred_edit_position ();
3429 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3430 align_region_internal ((*i)->region(), what, position);
3433 commit_reversible_command ();
3436 struct RegionSortByTime {
3437 bool operator() (const RegionView* a, const RegionView* b) {
3438 return a->region()->position() < b->region()->position();
3443 Editor::align_regions_relative (RegionPoint point)
3445 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3451 framepos_t const position = get_preferred_edit_position ();
3453 framepos_t distance = 0;
3457 list<RegionView*> sorted;
3458 rs.by_position (sorted);
3460 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3465 if (position > r->position()) {
3466 distance = position - r->position();
3468 distance = r->position() - position;
3474 if (position > r->last_frame()) {
3475 distance = position - r->last_frame();
3476 pos = r->position() + distance;
3478 distance = r->last_frame() - position;
3479 pos = r->position() - distance;
3485 pos = r->adjust_to_sync (position);
3486 if (pos > r->position()) {
3487 distance = pos - r->position();
3489 distance = r->position() - pos;
3495 if (pos == r->position()) {
3499 begin_reversible_command (_("align selection (relative)"));
3501 /* move first one specially */
3503 r->clear_changes ();
3504 r->set_position (pos);
3505 _session->add_command(new StatefulDiffCommand (r));
3507 /* move rest by the same amount */
3511 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3513 boost::shared_ptr<Region> region ((*i)->region());
3515 region->clear_changes ();
3518 region->set_position (region->position() + distance);
3520 region->set_position (region->position() - distance);
3523 _session->add_command(new StatefulDiffCommand (region));
3527 commit_reversible_command ();
3531 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3533 begin_reversible_command (_("align region"));
3534 align_region_internal (region, point, position);
3535 commit_reversible_command ();
3539 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3541 region->clear_changes ();
3545 region->set_position (region->adjust_to_sync (position));
3549 if (position > region->length()) {
3550 region->set_position (position - region->length());
3555 region->set_position (position);
3559 _session->add_command(new StatefulDiffCommand (region));
3563 Editor::trim_region_front ()
3569 Editor::trim_region_back ()
3571 trim_region (false);
3575 Editor::trim_region (bool front)
3577 framepos_t where = get_preferred_edit_position();
3578 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3584 begin_reversible_command (front ? _("trim front") : _("trim back"));
3586 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3587 if (!(*i)->region()->locked()) {
3589 (*i)->region()->clear_changes ();
3592 (*i)->region()->trim_front (where);
3593 maybe_locate_with_edit_preroll ( where );
3595 (*i)->region()->trim_end (where);
3596 maybe_locate_with_edit_preroll ( where );
3599 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3603 commit_reversible_command ();
3606 /** Trim the end of the selected regions to the position of the edit cursor */
3608 Editor::trim_region_to_loop ()
3610 Location* loc = _session->locations()->auto_loop_location();
3614 trim_region_to_location (*loc, _("trim to loop"));
3618 Editor::trim_region_to_punch ()
3620 Location* loc = _session->locations()->auto_punch_location();
3624 trim_region_to_location (*loc, _("trim to punch"));
3628 Editor::trim_region_to_location (const Location& loc, const char* str)
3630 RegionSelection rs = get_regions_from_selection_and_entered ();
3632 begin_reversible_command (str);
3634 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3635 RegionView* rv = (*x);
3637 /* require region to span proposed trim */
3638 switch (rv->region()->coverage (loc.start(), loc.end())) {
3639 case Evoral::OverlapInternal:
3645 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3654 if (tav->track() != 0) {
3655 speed = tav->track()->speed();
3658 start = session_frame_to_track_frame (loc.start(), speed);
3659 end = session_frame_to_track_frame (loc.end(), speed);
3661 rv->region()->clear_changes ();
3662 rv->region()->trim_to (start, (end - start));
3663 _session->add_command(new StatefulDiffCommand (rv->region()));
3666 commit_reversible_command ();
3670 Editor::trim_region_to_previous_region_end ()
3672 return trim_to_region(false);
3676 Editor::trim_region_to_next_region_start ()
3678 return trim_to_region(true);
3682 Editor::trim_to_region(bool forward)
3684 RegionSelection rs = get_regions_from_selection_and_entered ();
3686 begin_reversible_command (_("trim to region"));
3688 boost::shared_ptr<Region> next_region;
3690 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3692 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3698 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3706 if (atav->track() != 0) {
3707 speed = atav->track()->speed();
3711 boost::shared_ptr<Region> region = arv->region();
3712 boost::shared_ptr<Playlist> playlist (region->playlist());
3714 region->clear_changes ();
3718 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3724 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3725 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3729 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3735 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3737 arv->region_changed (ARDOUR::bounds_change);
3740 _session->add_command(new StatefulDiffCommand (region));
3743 commit_reversible_command ();
3747 Editor::unfreeze_route ()
3749 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3753 clicked_routeview->track()->unfreeze ();
3757 Editor::_freeze_thread (void* arg)
3759 return static_cast<Editor*>(arg)->freeze_thread ();
3763 Editor::freeze_thread ()
3765 /* create event pool because we may need to talk to the session */
3766 SessionEvent::create_per_thread_pool ("freeze events", 64);
3767 /* create per-thread buffers for process() tree to use */
3768 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3769 current_interthread_info->done = true;
3774 Editor::freeze_route ()
3780 /* stop transport before we start. this is important */
3782 _session->request_transport_speed (0.0);
3784 /* wait for just a little while, because the above call is asynchronous */
3786 Glib::usleep (250000);
3788 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3792 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3794 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3795 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3797 d.set_title (_("Cannot freeze"));
3802 if (clicked_routeview->track()->has_external_redirects()) {
3803 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"
3804 "Freezing will only process the signal as far as the first send/insert/return."),
3805 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3807 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3808 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3809 d.set_title (_("Freeze Limits"));
3811 int response = d.run ();
3814 case Gtk::RESPONSE_CANCEL:
3821 InterThreadInfo itt;
3822 current_interthread_info = &itt;
3824 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3826 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3828 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3830 while (!itt.done && !itt.cancel) {
3831 gtk_main_iteration ();
3834 current_interthread_info = 0;
3838 Editor::bounce_range_selection (bool replace, bool enable_processing)
3840 if (selection->time.empty()) {
3844 TrackSelection views = selection->tracks;
3846 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3848 if (enable_processing) {
3850 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3852 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3854 _("You can't perform this operation because the processing of the signal "
3855 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3856 "You can do this without processing, which is a different operation.")
3858 d.set_title (_("Cannot bounce"));
3865 framepos_t start = selection->time[clicked_selection].start;
3866 framepos_t end = selection->time[clicked_selection].end;
3867 framepos_t cnt = end - start + 1;
3869 begin_reversible_command (_("bounce range"));
3871 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3873 RouteTimeAxisView* rtv;
3875 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3879 boost::shared_ptr<Playlist> playlist;
3881 if ((playlist = rtv->playlist()) == 0) {
3885 InterThreadInfo itt;
3887 playlist->clear_changes ();
3888 playlist->clear_owned_changes ();
3890 boost::shared_ptr<Region> r;
3892 if (enable_processing) {
3893 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3895 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3903 list<AudioRange> ranges;
3904 ranges.push_back (AudioRange (start, start+cnt, 0));
3905 playlist->cut (ranges); // discard result
3906 playlist->add_region (r, start);
3909 vector<Command*> cmds;
3910 playlist->rdiff (cmds);
3911 _session->add_commands (cmds);
3913 _session->add_command (new StatefulDiffCommand (playlist));
3916 commit_reversible_command ();
3919 /** Delete selected regions, automation points or a time range */
3923 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3924 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3925 bool deleted = false;
3926 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3927 deleted = current_mixer_strip->delete_processors ();
3933 /** Cut selected regions, automation points or a time range */
3940 /** Copy selected regions, automation points or a time range */
3948 /** @return true if a Cut, Copy or Clear is possible */
3950 Editor::can_cut_copy () const
3952 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3959 /** Cut, copy or clear selected regions, automation points or a time range.
3960 * @param op Operation (Delete, Cut, Copy or Clear)
3963 Editor::cut_copy (CutCopyOp op)
3965 /* only cancel selection if cut/copy is successful.*/
3971 opname = _("delete");
3980 opname = _("clear");
3984 /* if we're deleting something, and the mouse is still pressed,
3985 the thing we started a drag for will be gone when we release
3986 the mouse button(s). avoid this. see part 2 at the end of
3990 if (op == Delete || op == Cut || op == Clear) {
3991 if (_drags->active ()) {
3996 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3997 cut_buffer->clear ();
3999 if (entered_marker) {
4001 /* cut/delete op while pointing at a marker */
4004 Location* loc = find_location_from_marker (entered_marker, ignored);
4006 if (_session && loc) {
4007 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4014 switch (mouse_mode) {
4017 begin_reversible_command (opname + ' ' + X_("MIDI"));
4019 commit_reversible_command ();
4025 bool did_edit = false;
4027 if (!selection->regions.empty() || !selection->points.empty()) {
4028 begin_reversible_command (opname + ' ' + _("objects"));
4031 if (!selection->regions.empty()) {
4032 cut_copy_regions (op, selection->regions);
4034 if (op == Cut || op == Delete) {
4035 selection->clear_regions ();
4039 if (!selection->points.empty()) {
4040 cut_copy_points (op);
4042 if (op == Cut || op == Delete) {
4043 selection->clear_points ();
4046 } else if (selection->time.empty()) {
4047 framepos_t start, end;
4048 /* no time selection, see if we can get an edit range
4051 if (get_edit_op_range (start, end)) {
4052 selection->set (start, end);
4054 } else if (!selection->time.empty()) {
4055 begin_reversible_command (opname + ' ' + _("range"));
4058 cut_copy_ranges (op);
4060 if (op == Cut || op == Delete) {
4061 selection->clear_time ();
4066 /* reset repeated paste state */
4069 commit_reversible_command ();
4072 if (op == Delete || op == Cut || op == Clear) {
4077 struct AutomationRecord {
4078 AutomationRecord () : state (0) , line(NULL) {}
4079 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4081 XMLNode* state; ///< state before any operation
4082 const AutomationLine* line; ///< line this came from
4083 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4086 /** Cut, copy or clear selected automation points.
4087 * @param op Operation (Cut, Copy or Clear)
4090 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4092 if (selection->points.empty ()) {
4096 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4097 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4099 /* Keep a record of the AutomationLists that we end up using in this operation */
4100 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4103 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4104 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4105 const AutomationLine& line = (*i)->line();
4106 const boost::shared_ptr<AutomationList> al = line.the_list();
4107 if (lists.find (al) == lists.end ()) {
4108 /* We haven't seen this list yet, so make a record for it. This includes
4109 taking a copy of its current state, in case this is needed for undo later.
4111 lists[al] = AutomationRecord (&al->get_state (), &line);
4115 if (op == Cut || op == Copy) {
4116 /* This operation will involve putting things in the cut buffer, so create an empty
4117 ControlList for each of our source lists to put the cut buffer data in.
4119 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4120 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4123 /* Add all selected points to the relevant copy ControlLists */
4124 framepos_t start = std::numeric_limits<framepos_t>::max();
4125 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4126 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4127 AutomationList::const_iterator j = (*i)->model();
4129 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4131 /* Update earliest MIDI start time in beats */
4132 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4134 /* Update earliest session start time in frames */
4135 start = std::min(start, (*i)->line().session_position(j));
4139 /* Snap start time backwards, so copy/paste is snap aligned. */
4141 if (earliest == Evoral::Beats::max()) {
4142 earliest = Evoral::Beats(); // Weird... don't offset
4144 earliest.round_down_to_beat();
4146 if (start == std::numeric_limits<double>::max()) {
4147 start = 0; // Weird... don't offset
4149 snap_to(start, RoundDownMaybe);
4152 const double line_offset = midi ? earliest.to_double() : start;
4153 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4154 /* Correct this copy list so that it is relative to the earliest
4155 start time, so relative ordering between points is preserved
4156 when copying from several lists and the paste starts at the
4157 earliest copied piece of data. */
4158 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4159 (*j)->when -= line_offset;
4162 /* And add it to the cut buffer */
4163 cut_buffer->add (i->second.copy);
4167 if (op == Delete || op == Cut) {
4168 /* This operation needs to remove things from the main AutomationList, so do that now */
4170 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4171 i->first->freeze ();
4174 /* Remove each selected point from its AutomationList */
4175 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4176 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4177 al->erase ((*i)->model ());
4180 /* Thaw the lists and add undo records for them */
4181 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4182 boost::shared_ptr<AutomationList> al = i->first;
4184 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4189 /** Cut, copy or clear selected automation points.
4190 * @param op Operation (Cut, Copy or Clear)
4193 Editor::cut_copy_midi (CutCopyOp op)
4195 Evoral::Beats earliest = Evoral::Beats::max();
4196 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4197 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4199 if (!mrv->selection().empty()) {
4200 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4202 mrv->cut_copy_clear (op);
4204 /* XXX: not ideal, as there may be more than one track involved in the selection */
4205 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4209 if (!selection->points.empty()) {
4210 cut_copy_points (op, earliest, true);
4211 if (op == Cut || op == Delete) {
4212 selection->clear_points ();
4217 struct lt_playlist {
4218 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4219 return a.playlist < b.playlist;
4223 struct PlaylistMapping {
4225 boost::shared_ptr<Playlist> pl;
4227 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4230 /** Remove `clicked_regionview' */
4232 Editor::remove_clicked_region ()
4234 if (clicked_routeview == 0 || clicked_regionview == 0) {
4238 begin_reversible_command (_("remove region"));
4240 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4242 playlist->clear_changes ();
4243 playlist->clear_owned_changes ();
4244 playlist->remove_region (clicked_regionview->region());
4245 if (Config->get_edit_mode() == Ripple)
4246 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4248 /* We might have removed regions, which alters other regions' layering_index,
4249 so we need to do a recursive diff here.
4251 vector<Command*> cmds;
4252 playlist->rdiff (cmds);
4253 _session->add_commands (cmds);
4255 _session->add_command(new StatefulDiffCommand (playlist));
4256 commit_reversible_command ();
4260 /** Remove the selected regions */
4262 Editor::remove_selected_regions ()
4264 RegionSelection rs = get_regions_from_selection_and_entered ();
4266 if (!_session || rs.empty()) {
4270 begin_reversible_command (_("remove region"));
4272 list<boost::shared_ptr<Region> > regions_to_remove;
4274 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4275 // we can't just remove the region(s) in this loop because
4276 // this removes them from the RegionSelection, and they thus
4277 // disappear from underneath the iterator, and the ++i above
4278 // SEGVs in a puzzling fashion.
4280 // so, first iterate over the regions to be removed from rs and
4281 // add them to the regions_to_remove list, and then
4282 // iterate over the list to actually remove them.
4284 regions_to_remove.push_back ((*i)->region());
4287 vector<boost::shared_ptr<Playlist> > playlists;
4289 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4291 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4294 // is this check necessary?
4298 /* get_regions_from_selection_and_entered() guarantees that
4299 the playlists involved are unique, so there is no need
4303 playlists.push_back (playlist);
4305 playlist->clear_changes ();
4306 playlist->clear_owned_changes ();
4307 playlist->freeze ();
4308 playlist->remove_region (*rl);
4309 if (Config->get_edit_mode() == Ripple)
4310 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4314 vector<boost::shared_ptr<Playlist> >::iterator pl;
4316 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4319 /* We might have removed regions, which alters other regions' layering_index,
4320 so we need to do a recursive diff here.
4322 vector<Command*> cmds;
4323 (*pl)->rdiff (cmds);
4324 _session->add_commands (cmds);
4326 _session->add_command(new StatefulDiffCommand (*pl));
4329 commit_reversible_command ();
4332 /** Cut, copy or clear selected regions.
4333 * @param op Operation (Cut, Copy or Clear)
4336 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4338 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4339 a map when we want ordered access to both elements. i think.
4342 vector<PlaylistMapping> pmap;
4344 framepos_t first_position = max_framepos;
4346 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4347 FreezeList freezelist;
4349 /* get ordering correct before we cut/copy */
4351 rs.sort_by_position_and_track ();
4353 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4355 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4357 if (op == Cut || op == Clear || op == Delete) {
4358 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4361 FreezeList::iterator fl;
4363 // only take state if this is a new playlist.
4364 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4370 if (fl == freezelist.end()) {
4371 pl->clear_changes();
4372 pl->clear_owned_changes ();
4374 freezelist.insert (pl);
4379 TimeAxisView* tv = &(*x)->get_time_axis_view();
4380 vector<PlaylistMapping>::iterator z;
4382 for (z = pmap.begin(); z != pmap.end(); ++z) {
4383 if ((*z).tv == tv) {
4388 if (z == pmap.end()) {
4389 pmap.push_back (PlaylistMapping (tv));
4393 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4395 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4398 /* region not yet associated with a playlist (e.g. unfinished
4405 TimeAxisView& tv = (*x)->get_time_axis_view();
4406 boost::shared_ptr<Playlist> npl;
4407 RegionSelection::iterator tmp;
4414 vector<PlaylistMapping>::iterator z;
4416 for (z = pmap.begin(); z != pmap.end(); ++z) {
4417 if ((*z).tv == &tv) {
4422 assert (z != pmap.end());
4425 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4433 boost::shared_ptr<Region> r = (*x)->region();
4434 boost::shared_ptr<Region> _xx;
4440 pl->remove_region (r);
4441 if (Config->get_edit_mode() == Ripple)
4442 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4446 _xx = RegionFactory::create (r);
4447 npl->add_region (_xx, r->position() - first_position);
4448 pl->remove_region (r);
4449 if (Config->get_edit_mode() == Ripple)
4450 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4454 /* copy region before adding, so we're not putting same object into two different playlists */
4455 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4459 pl->remove_region (r);
4460 if (Config->get_edit_mode() == Ripple)
4461 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4470 list<boost::shared_ptr<Playlist> > foo;
4472 /* the pmap is in the same order as the tracks in which selected regions occured */
4474 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4477 foo.push_back ((*i).pl);
4482 cut_buffer->set (foo);
4486 _last_cut_copy_source_track = 0;
4488 _last_cut_copy_source_track = pmap.front().tv;
4492 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4495 /* We might have removed regions, which alters other regions' layering_index,
4496 so we need to do a recursive diff here.
4498 vector<Command*> cmds;
4499 (*pl)->rdiff (cmds);
4500 _session->add_commands (cmds);
4502 _session->add_command (new StatefulDiffCommand (*pl));
4507 Editor::cut_copy_ranges (CutCopyOp op)
4509 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4511 /* Sort the track selection now, so that it if is used, the playlists
4512 selected by the calls below to cut_copy_clear are in the order that
4513 their tracks appear in the editor. This makes things like paste
4514 of ranges work properly.
4517 sort_track_selection (ts);
4520 if (!entered_track) {
4523 ts.push_back (entered_track);
4526 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4527 (*i)->cut_copy_clear (*selection, op);
4532 Editor::paste (float times, bool from_context)
4534 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4536 paste_internal (get_preferred_edit_position (false, from_context), times);
4540 Editor::mouse_paste ()
4545 if (!mouse_frame (where, ignored)) {
4550 paste_internal (where, 1);
4554 Editor::paste_internal (framepos_t position, float times)
4556 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4558 if (cut_buffer->empty(internal_editing())) {
4562 if (position == max_framepos) {
4563 position = get_preferred_edit_position();
4564 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4567 if (position == last_paste_pos) {
4568 /* repeated paste in the same position */
4571 /* paste in new location, reset repeated paste state */
4573 last_paste_pos = position;
4576 /* get everything in the correct order */
4579 if (!selection->tracks.empty()) {
4580 /* If there is a track selection, paste into exactly those tracks and
4581 only those tracks. This allows the user to be explicit and override
4582 the below "do the reasonable thing" logic. */
4583 ts = selection->tracks.filter_to_unique_playlists ();
4584 sort_track_selection (ts);
4586 /* Figure out which track to base the paste at. */
4587 TimeAxisView* base_track = NULL;
4588 if (_edit_point == Editing::EditAtMouse && entered_track) {
4589 /* With the mouse edit point, paste onto the track under the mouse. */
4590 base_track = entered_track;
4591 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4592 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4593 base_track = &entered_regionview->get_time_axis_view();
4594 } else if (_last_cut_copy_source_track) {
4595 /* Paste to the track that the cut/copy came from (see mantis #333). */
4596 base_track = _last_cut_copy_source_track;
4598 /* This is "impossible" since we've copied... well, do nothing. */
4602 /* Walk up to parent if necessary, so base track is a route. */
4603 while (base_track->get_parent()) {
4604 base_track = base_track->get_parent();
4607 /* Add base track and all tracks below it. The paste logic will select
4608 the appropriate object types from the cut buffer in relative order. */
4609 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4610 if ((*i)->order() >= base_track->order()) {
4615 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4616 sort_track_selection (ts);
4618 /* Add automation children of each track in order, for pasting several lines. */
4619 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4620 /* Add any automation children for pasting several lines */
4621 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4626 typedef RouteTimeAxisView::AutomationTracks ATracks;
4627 const ATracks& atracks = rtv->automation_tracks();
4628 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4629 i = ts.insert(i, a->second.get());
4634 /* We now have a list of trackviews starting at base_track, including
4635 automation children, in the order shown in the editor, e.g. R1,
4636 R1.A1, R1.A2, R2, R2.A1, ... */
4639 begin_reversible_command (Operations::paste);
4641 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4642 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4643 /* Only one line copied, and one automation track selected. Do a
4644 "greedy" paste from one automation type to another. */
4646 PasteContext ctx(paste_count, times, ItemCounts(), true);
4647 ts.front()->paste (position, *cut_buffer, ctx);
4651 /* Paste into tracks */
4653 PasteContext ctx(paste_count, times, ItemCounts(), false);
4654 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4655 (*i)->paste (position, *cut_buffer, ctx);
4659 commit_reversible_command ();
4663 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4665 boost::shared_ptr<Playlist> playlist;
4666 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4667 RegionSelection foo;
4669 framepos_t const start_frame = regions.start ();
4670 framepos_t const end_frame = regions.end_frame ();
4672 begin_reversible_command (Operations::duplicate_region);
4674 selection->clear_regions ();
4676 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4678 boost::shared_ptr<Region> r ((*i)->region());
4680 TimeAxisView& tv = (*i)->get_time_axis_view();
4681 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4682 latest_regionviews.clear ();
4683 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4685 playlist = (*i)->region()->playlist();
4686 playlist->clear_changes ();
4687 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4688 _session->add_command(new StatefulDiffCommand (playlist));
4692 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4696 selection->set (foo);
4699 commit_reversible_command ();
4703 Editor::duplicate_selection (float times)
4705 if (selection->time.empty() || selection->tracks.empty()) {
4709 boost::shared_ptr<Playlist> playlist;
4710 vector<boost::shared_ptr<Region> > new_regions;
4711 vector<boost::shared_ptr<Region> >::iterator ri;
4713 create_region_from_selection (new_regions);
4715 if (new_regions.empty()) {
4719 begin_reversible_command (_("duplicate selection"));
4721 ri = new_regions.begin();
4723 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4725 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4726 if ((playlist = (*i)->playlist()) == 0) {
4729 playlist->clear_changes ();
4731 if (clicked_selection) {
4732 end = selection->time[clicked_selection].end;
4734 end = selection->time.end_frame();
4736 playlist->duplicate (*ri, end, times);
4737 _session->add_command (new StatefulDiffCommand (playlist));
4740 if (ri == new_regions.end()) {
4745 commit_reversible_command ();
4748 /** Reset all selected points to the relevant default value */
4750 Editor::reset_point_selection ()
4752 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4753 ARDOUR::AutomationList::iterator j = (*i)->model ();
4754 (*j)->value = (*i)->line().the_list()->default_value ();
4759 Editor::center_playhead ()
4761 float const page = _visible_canvas_width * samples_per_pixel;
4762 center_screen_internal (playhead_cursor->current_frame (), page);
4766 Editor::center_edit_point ()
4768 float const page = _visible_canvas_width * samples_per_pixel;
4769 center_screen_internal (get_preferred_edit_position(), page);
4772 /** Caller must begin and commit a reversible command */
4774 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4776 playlist->clear_changes ();
4778 _session->add_command (new StatefulDiffCommand (playlist));
4782 Editor::nudge_track (bool use_edit, bool forwards)
4784 boost::shared_ptr<Playlist> playlist;
4785 framepos_t distance;
4786 framepos_t next_distance;
4790 start = get_preferred_edit_position();
4795 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4799 if (selection->tracks.empty()) {
4803 begin_reversible_command (_("nudge track"));
4805 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4807 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4809 if ((playlist = (*i)->playlist()) == 0) {
4813 playlist->clear_changes ();
4814 playlist->clear_owned_changes ();
4816 playlist->nudge_after (start, distance, forwards);
4818 vector<Command*> cmds;
4820 playlist->rdiff (cmds);
4821 _session->add_commands (cmds);
4823 _session->add_command (new StatefulDiffCommand (playlist));
4826 commit_reversible_command ();
4830 Editor::remove_last_capture ()
4832 vector<string> choices;
4839 if (Config->get_verify_remove_last_capture()) {
4840 prompt = _("Do you really want to destroy the last capture?"
4841 "\n(This is destructive and cannot be undone)");
4843 choices.push_back (_("No, do nothing."));
4844 choices.push_back (_("Yes, destroy it."));
4846 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4848 if (prompter.run () == 1) {
4849 _session->remove_last_capture ();
4850 _regions->redisplay ();
4854 _session->remove_last_capture();
4855 _regions->redisplay ();
4860 Editor::normalize_region ()
4866 RegionSelection rs = get_regions_from_selection_and_entered ();
4872 NormalizeDialog dialog (rs.size() > 1);
4874 if (dialog.run () == RESPONSE_CANCEL) {
4878 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4881 /* XXX: should really only count audio regions here */
4882 int const regions = rs.size ();
4884 /* Make a list of the selected audio regions' maximum amplitudes, and also
4885 obtain the maximum amplitude of them all.
4887 list<double> max_amps;
4889 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4890 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4892 dialog.descend (1.0 / regions);
4893 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4896 /* the user cancelled the operation */
4900 max_amps.push_back (a);
4901 max_amp = max (max_amp, a);
4906 begin_reversible_command (_("normalize"));
4908 list<double>::const_iterator a = max_amps.begin ();
4910 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4911 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4916 arv->region()->clear_changes ();
4918 double const amp = dialog.normalize_individually() ? *a : max_amp;
4920 arv->audio_region()->normalize (amp, dialog.target ());
4921 _session->add_command (new StatefulDiffCommand (arv->region()));
4926 commit_reversible_command ();
4931 Editor::reset_region_scale_amplitude ()
4937 RegionSelection rs = get_regions_from_selection_and_entered ();
4943 begin_reversible_command ("reset gain");
4945 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4946 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4949 arv->region()->clear_changes ();
4950 arv->audio_region()->set_scale_amplitude (1.0f);
4951 _session->add_command (new StatefulDiffCommand (arv->region()));
4954 commit_reversible_command ();
4958 Editor::adjust_region_gain (bool up)
4960 RegionSelection rs = get_regions_from_selection_and_entered ();
4962 if (!_session || rs.empty()) {
4966 begin_reversible_command ("adjust region gain");
4968 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4969 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4974 arv->region()->clear_changes ();
4976 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4984 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4985 _session->add_command (new StatefulDiffCommand (arv->region()));
4988 commit_reversible_command ();
4993 Editor::reverse_region ()
4999 Reverse rev (*_session);
5000 apply_filter (rev, _("reverse regions"));
5004 Editor::strip_region_silence ()
5010 RegionSelection rs = get_regions_from_selection_and_entered ();
5016 std::list<RegionView*> audio_only;
5018 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5019 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5021 audio_only.push_back (arv);
5025 StripSilenceDialog d (_session, audio_only);
5026 int const r = d.run ();
5030 if (r == Gtk::RESPONSE_OK) {
5031 ARDOUR::AudioIntervalMap silences;
5032 d.silences (silences);
5033 StripSilence s (*_session, silences, d.fade_length());
5034 apply_filter (s, _("strip silence"), &d);
5039 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5041 Evoral::Sequence<Evoral::Beats>::Notes selected;
5042 mrv.selection_as_notelist (selected, true);
5044 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5045 v.push_back (selected);
5047 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5048 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5050 return op (mrv.midi_region()->model(), pos_beats, v);
5054 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5060 begin_reversible_command (op.name ());
5062 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5063 RegionSelection::const_iterator tmp = r;
5066 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5069 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5072 _session->add_command (cmd);
5079 commit_reversible_command ();
5083 Editor::fork_region ()
5085 RegionSelection rs = get_regions_from_selection_and_entered ();
5091 begin_reversible_command (_("Fork Region(s)"));
5093 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5096 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5097 RegionSelection::iterator tmp = r;
5100 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5104 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5105 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5106 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5108 playlist->clear_changes ();
5109 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5110 _session->add_command(new StatefulDiffCommand (playlist));
5112 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5119 commit_reversible_command ();
5123 Editor::quantize_region ()
5126 quantize_regions(get_regions_from_selection_and_entered ());
5131 Editor::quantize_regions (const RegionSelection& rs)
5133 if (rs.n_midi_regions() == 0) {
5137 QuantizeDialog* qd = new QuantizeDialog (*this);
5140 const int r = qd->run ();
5143 if (r == Gtk::RESPONSE_OK) {
5144 Quantize quant (qd->snap_start(), qd->snap_end(),
5145 qd->start_grid_size(), qd->end_grid_size(),
5146 qd->strength(), qd->swing(), qd->threshold());
5148 apply_midi_note_edit_op (quant, rs);
5153 Editor::legatize_region (bool shrink_only)
5156 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5161 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5163 if (rs.n_midi_regions() == 0) {
5167 Legatize legatize(shrink_only);
5168 apply_midi_note_edit_op (legatize, rs);
5172 Editor::transform_region ()
5175 transform_regions(get_regions_from_selection_and_entered ());
5180 Editor::transform_regions (const RegionSelection& rs)
5182 if (rs.n_midi_regions() == 0) {
5186 TransformDialog* td = new TransformDialog();
5189 const int r = td->run();
5192 if (r == Gtk::RESPONSE_OK) {
5193 Transform transform(td->get());
5194 apply_midi_note_edit_op(transform, rs);
5199 Editor::insert_patch_change (bool from_context)
5201 RegionSelection rs = get_regions_from_selection_and_entered ();
5207 const framepos_t p = get_preferred_edit_position (false, from_context);
5209 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5210 there may be more than one, but the PatchChangeDialog can only offer
5211 one set of patch menus.
5213 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5215 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5216 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5218 if (d.run() == RESPONSE_CANCEL) {
5222 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5223 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5225 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5226 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5233 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5235 RegionSelection rs = get_regions_from_selection_and_entered ();
5241 begin_reversible_command (command);
5243 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5247 int const N = rs.size ();
5249 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5250 RegionSelection::iterator tmp = r;
5253 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5255 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5258 progress->descend (1.0 / N);
5261 if (arv->audio_region()->apply (filter, progress) == 0) {
5263 playlist->clear_changes ();
5264 playlist->clear_owned_changes ();
5266 if (filter.results.empty ()) {
5268 /* no regions returned; remove the old one */
5269 playlist->remove_region (arv->region ());
5273 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5275 /* first region replaces the old one */
5276 playlist->replace_region (arv->region(), *res, (*res)->position());
5280 while (res != filter.results.end()) {
5281 playlist->add_region (*res, (*res)->position());
5287 /* We might have removed regions, which alters other regions' layering_index,
5288 so we need to do a recursive diff here.
5290 vector<Command*> cmds;
5291 playlist->rdiff (cmds);
5292 _session->add_commands (cmds);
5294 _session->add_command(new StatefulDiffCommand (playlist));
5300 progress->ascend ();
5308 commit_reversible_command ();
5312 Editor::external_edit_region ()
5318 Editor::reset_region_gain_envelopes ()
5320 RegionSelection rs = get_regions_from_selection_and_entered ();
5322 if (!_session || rs.empty()) {
5326 begin_reversible_command (_("reset region gain"));
5328 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5329 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5331 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5332 XMLNode& before (alist->get_state());
5334 arv->audio_region()->set_default_envelope ();
5335 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5339 commit_reversible_command ();
5343 Editor::set_region_gain_visibility (RegionView* rv)
5345 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5347 arv->update_envelope_visibility();
5352 Editor::set_gain_envelope_visibility ()
5358 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5359 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5361 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5367 Editor::toggle_gain_envelope_active ()
5369 if (_ignore_region_action) {
5373 RegionSelection rs = get_regions_from_selection_and_entered ();
5375 if (!_session || rs.empty()) {
5379 begin_reversible_command (_("region gain envelope active"));
5381 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5382 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5384 arv->region()->clear_changes ();
5385 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5386 _session->add_command (new StatefulDiffCommand (arv->region()));
5390 commit_reversible_command ();
5394 Editor::toggle_region_lock ()
5396 if (_ignore_region_action) {
5400 RegionSelection rs = get_regions_from_selection_and_entered ();
5402 if (!_session || rs.empty()) {
5406 begin_reversible_command (_("toggle region lock"));
5408 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5409 (*i)->region()->clear_changes ();
5410 (*i)->region()->set_locked (!(*i)->region()->locked());
5411 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5414 commit_reversible_command ();
5418 Editor::toggle_region_video_lock ()
5420 if (_ignore_region_action) {
5424 RegionSelection rs = get_regions_from_selection_and_entered ();
5426 if (!_session || rs.empty()) {
5430 begin_reversible_command (_("Toggle Video Lock"));
5432 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5433 (*i)->region()->clear_changes ();
5434 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5435 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5438 commit_reversible_command ();
5442 Editor::toggle_region_lock_style ()
5444 if (_ignore_region_action) {
5448 RegionSelection rs = get_regions_from_selection_and_entered ();
5450 if (!_session || rs.empty()) {
5454 begin_reversible_command (_("region lock style"));
5456 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5457 (*i)->region()->clear_changes ();
5458 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5459 (*i)->region()->set_position_lock_style (ns);
5460 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5463 commit_reversible_command ();
5467 Editor::toggle_opaque_region ()
5469 if (_ignore_region_action) {
5473 RegionSelection rs = get_regions_from_selection_and_entered ();
5475 if (!_session || rs.empty()) {
5479 begin_reversible_command (_("change region opacity"));
5481 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5482 (*i)->region()->clear_changes ();
5483 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5484 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5487 commit_reversible_command ();
5491 Editor::toggle_record_enable ()
5493 bool new_state = false;
5495 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5496 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5499 if (!rtav->is_track())
5503 new_state = !rtav->track()->record_enabled();
5507 rtav->track()->set_record_enabled (new_state, this);
5512 Editor::toggle_solo ()
5514 bool new_state = false;
5516 boost::shared_ptr<RouteList> rl (new RouteList);
5518 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5519 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5526 new_state = !rtav->route()->soloed ();
5530 rl->push_back (rtav->route());
5533 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5537 Editor::toggle_mute ()
5539 bool new_state = false;
5541 boost::shared_ptr<RouteList> rl (new RouteList);
5543 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5544 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5551 new_state = !rtav->route()->muted();
5555 rl->push_back (rtav->route());
5558 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5562 Editor::toggle_solo_isolate ()
5568 Editor::fade_range ()
5570 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5572 begin_reversible_command (_("fade range"));
5574 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5575 (*i)->fade_range (selection->time);
5578 commit_reversible_command ();
5583 Editor::set_fade_length (bool in)
5585 RegionSelection rs = get_regions_from_selection_and_entered ();
5591 /* we need a region to measure the offset from the start */
5593 RegionView* rv = rs.front ();
5595 framepos_t pos = get_preferred_edit_position();
5599 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5600 /* edit point is outside the relevant region */
5605 if (pos <= rv->region()->position()) {
5609 len = pos - rv->region()->position();
5610 cmd = _("set fade in length");
5612 if (pos >= rv->region()->last_frame()) {
5616 len = rv->region()->last_frame() - pos;
5617 cmd = _("set fade out length");
5620 begin_reversible_command (cmd);
5622 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5623 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5629 boost::shared_ptr<AutomationList> alist;
5631 alist = tmp->audio_region()->fade_in();
5633 alist = tmp->audio_region()->fade_out();
5636 XMLNode &before = alist->get_state();
5639 tmp->audio_region()->set_fade_in_length (len);
5640 tmp->audio_region()->set_fade_in_active (true);
5642 tmp->audio_region()->set_fade_out_length (len);
5643 tmp->audio_region()->set_fade_out_active (true);
5646 XMLNode &after = alist->get_state();
5647 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5650 commit_reversible_command ();
5654 Editor::set_fade_in_shape (FadeShape shape)
5656 RegionSelection rs = get_regions_from_selection_and_entered ();
5662 begin_reversible_command (_("set fade in shape"));
5664 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5665 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5671 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5672 XMLNode &before = alist->get_state();
5674 tmp->audio_region()->set_fade_in_shape (shape);
5676 XMLNode &after = alist->get_state();
5677 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5680 commit_reversible_command ();
5685 Editor::set_fade_out_shape (FadeShape shape)
5687 RegionSelection rs = get_regions_from_selection_and_entered ();
5693 begin_reversible_command (_("set fade out shape"));
5695 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5696 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5702 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5703 XMLNode &before = alist->get_state();
5705 tmp->audio_region()->set_fade_out_shape (shape);
5707 XMLNode &after = alist->get_state();
5708 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5711 commit_reversible_command ();
5715 Editor::set_fade_in_active (bool yn)
5717 RegionSelection rs = get_regions_from_selection_and_entered ();
5723 begin_reversible_command (_("set fade in active"));
5725 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5726 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5733 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5735 ar->clear_changes ();
5736 ar->set_fade_in_active (yn);
5737 _session->add_command (new StatefulDiffCommand (ar));
5740 commit_reversible_command ();
5744 Editor::set_fade_out_active (bool yn)
5746 RegionSelection rs = get_regions_from_selection_and_entered ();
5752 begin_reversible_command (_("set fade out active"));
5754 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5755 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5761 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5763 ar->clear_changes ();
5764 ar->set_fade_out_active (yn);
5765 _session->add_command(new StatefulDiffCommand (ar));
5768 commit_reversible_command ();
5772 Editor::toggle_region_fades (int dir)
5774 if (_ignore_region_action) {
5778 boost::shared_ptr<AudioRegion> ar;
5781 RegionSelection rs = get_regions_from_selection_and_entered ();
5787 RegionSelection::iterator i;
5788 for (i = rs.begin(); i != rs.end(); ++i) {
5789 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5791 yn = ar->fade_out_active ();
5793 yn = ar->fade_in_active ();
5799 if (i == rs.end()) {
5803 /* XXX should this undo-able? */
5805 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5806 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5809 if (dir == 1 || dir == 0) {
5810 ar->set_fade_in_active (!yn);
5813 if (dir == -1 || dir == 0) {
5814 ar->set_fade_out_active (!yn);
5820 /** Update region fade visibility after its configuration has been changed */
5822 Editor::update_region_fade_visibility ()
5824 bool _fade_visibility = _session->config.get_show_region_fades ();
5826 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5827 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5829 if (_fade_visibility) {
5830 v->audio_view()->show_all_fades ();
5832 v->audio_view()->hide_all_fades ();
5839 Editor::set_edit_point ()
5844 if (!mouse_frame (where, ignored)) {
5850 if (selection->markers.empty()) {
5852 mouse_add_new_marker (where);
5857 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5860 loc->move_to (where);
5866 Editor::set_playhead_cursor ()
5868 if (entered_marker) {
5869 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5874 if (!mouse_frame (where, ignored)) {
5881 _session->request_locate (where, _session->transport_rolling());
5885 if (ARDOUR_UI::config()->get_follow_edits()) {
5886 cancel_time_selection();
5891 Editor::split_region ()
5893 //if a range is selected, separate it
5894 if ( !selection->time.empty()) {
5895 separate_regions_between (selection->time);
5899 //if no range was selected, try to find some regions to split
5900 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
5902 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5904 framepos_t where = get_preferred_edit_position ();
5910 split_regions_at (where, rs);
5914 struct EditorOrderRouteSorter {
5915 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5916 return a->order_key () < b->order_key ();
5921 Editor::select_next_route()
5923 if (selection->tracks.empty()) {
5924 selection->set (track_views.front());
5928 TimeAxisView* current = selection->tracks.front();
5932 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5933 if (*i == current) {
5935 if (i != track_views.end()) {
5938 current = (*(track_views.begin()));
5939 //selection->set (*(track_views.begin()));
5944 rui = dynamic_cast<RouteUI *>(current);
5945 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5947 selection->set(current);
5949 ensure_time_axis_view_is_visible (*current, false);
5953 Editor::select_prev_route()
5955 if (selection->tracks.empty()) {
5956 selection->set (track_views.front());
5960 TimeAxisView* current = selection->tracks.front();
5964 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5965 if (*i == current) {
5967 if (i != track_views.rend()) {
5970 current = *(track_views.rbegin());
5975 rui = dynamic_cast<RouteUI *>(current);
5976 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5978 selection->set (current);
5980 ensure_time_axis_view_is_visible (*current, false);
5984 Editor::set_loop_from_selection (bool play)
5986 if (_session == 0) {
5990 framepos_t start, end;
5991 if (!get_selection_extents ( start, end))
5994 set_loop_range (start, end, _("set loop range from selection"));
5997 _session->request_play_loop (true, true);
6002 Editor::set_loop_from_region (bool play)
6004 framepos_t start, end;
6005 if (!get_selection_extents ( start, end))
6008 set_loop_range (start, end, _("set loop range from region"));
6011 _session->request_locate (start, true);
6012 _session->request_play_loop (true);
6017 Editor::set_punch_from_selection ()
6019 if (_session == 0) {
6023 framepos_t start, end;
6024 if (!get_selection_extents ( start, end))
6027 set_punch_range (start, end, _("set punch range from selection"));
6031 Editor::set_session_extents_from_selection ()
6033 if (_session == 0) {
6037 framepos_t start, end;
6038 if (!get_selection_extents ( start, end))
6041 begin_reversible_command (_("set session start/end from selection"));
6044 if ((loc = _session->locations()->session_range_location()) == 0) {
6045 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6047 XMLNode &before = loc->get_state();
6049 _session->set_session_extents ( start, end );
6051 XMLNode &after = loc->get_state();
6053 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6055 commit_reversible_command ();
6060 Editor::set_punch_from_region ()
6062 framepos_t start, end;
6063 if (!get_selection_extents ( start, end))
6066 set_punch_range (start, end, _("set punch range from region"));
6070 Editor::pitch_shift_region ()
6072 RegionSelection rs = get_regions_from_selection_and_entered ();
6074 RegionSelection audio_rs;
6075 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6076 if (dynamic_cast<AudioRegionView*> (*i)) {
6077 audio_rs.push_back (*i);
6081 if (audio_rs.empty()) {
6085 pitch_shift (audio_rs, 1.2);
6089 Editor::transpose_region ()
6091 RegionSelection rs = get_regions_from_selection_and_entered ();
6093 list<MidiRegionView*> midi_region_views;
6094 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6095 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6097 midi_region_views.push_back (mrv);
6102 int const r = d.run ();
6103 if (r != RESPONSE_ACCEPT) {
6107 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6108 (*i)->midi_region()->transpose (d.semitones ());
6113 Editor::set_tempo_from_region ()
6115 RegionSelection rs = get_regions_from_selection_and_entered ();
6117 if (!_session || rs.empty()) {
6121 RegionView* rv = rs.front();
6123 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6127 Editor::use_range_as_bar ()
6129 framepos_t start, end;
6130 if (get_edit_op_range (start, end)) {
6131 define_one_bar (start, end);
6136 Editor::define_one_bar (framepos_t start, framepos_t end)
6138 framepos_t length = end - start;
6140 const Meter& m (_session->tempo_map().meter_at (start));
6142 /* length = 1 bar */
6144 /* now we want frames per beat.
6145 we have frames per bar, and beats per bar, so ...
6148 /* XXXX METER MATH */
6150 double frames_per_beat = length / m.divisions_per_bar();
6152 /* beats per minute = */
6154 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6156 /* now decide whether to:
6158 (a) set global tempo
6159 (b) add a new tempo marker
6163 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6165 bool do_global = false;
6167 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6169 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6170 at the start, or create a new marker
6173 vector<string> options;
6174 options.push_back (_("Cancel"));
6175 options.push_back (_("Add new marker"));
6176 options.push_back (_("Set global tempo"));
6179 _("Define one bar"),
6180 _("Do you want to set the global tempo or add a new tempo marker?"),
6184 c.set_default_response (2);
6200 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6201 if the marker is at the region starter, change it, otherwise add
6206 begin_reversible_command (_("set tempo from region"));
6207 XMLNode& before (_session->tempo_map().get_state());
6210 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6211 } else if (t.frame() == start) {
6212 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6214 Timecode::BBT_Time bbt;
6215 _session->tempo_map().bbt_time (start, bbt);
6216 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6219 XMLNode& after (_session->tempo_map().get_state());
6221 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6222 commit_reversible_command ();
6226 Editor::split_region_at_transients ()
6228 AnalysisFeatureList positions;
6230 RegionSelection rs = get_regions_from_selection_and_entered ();
6232 if (!_session || rs.empty()) {
6236 begin_reversible_command (_("split regions"));
6238 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6240 RegionSelection::iterator tmp;
6245 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6247 if (ar && (ar->get_transients (positions) == 0)) {
6248 split_region_at_points ((*i)->region(), positions, true);
6255 commit_reversible_command ();
6260 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6262 bool use_rhythmic_rodent = false;
6264 boost::shared_ptr<Playlist> pl = r->playlist();
6266 list<boost::shared_ptr<Region> > new_regions;
6272 if (positions.empty()) {
6277 if (positions.size() > 20 && can_ferret) {
6278 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);
6279 MessageDialog msg (msgstr,
6282 Gtk::BUTTONS_OK_CANCEL);
6285 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6286 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6288 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6291 msg.set_title (_("Excessive split?"));
6294 int response = msg.run();
6300 case RESPONSE_APPLY:
6301 use_rhythmic_rodent = true;
6308 if (use_rhythmic_rodent) {
6309 show_rhythm_ferret ();
6313 AnalysisFeatureList::const_iterator x;
6315 pl->clear_changes ();
6316 pl->clear_owned_changes ();
6318 x = positions.begin();
6320 if (x == positions.end()) {
6325 pl->remove_region (r);
6329 while (x != positions.end()) {
6331 /* deal with positons that are out of scope of present region bounds */
6332 if (*x <= 0 || *x > r->length()) {
6337 /* file start = original start + how far we from the initial position ?
6340 framepos_t file_start = r->start() + pos;
6342 /* length = next position - current position
6345 framepos_t len = (*x) - pos;
6347 /* XXX we do we really want to allow even single-sample regions?
6348 shouldn't we have some kind of lower limit on region size?
6357 if (RegionFactory::region_name (new_name, r->name())) {
6361 /* do NOT announce new regions 1 by one, just wait till they are all done */
6365 plist.add (ARDOUR::Properties::start, file_start);
6366 plist.add (ARDOUR::Properties::length, len);
6367 plist.add (ARDOUR::Properties::name, new_name);
6368 plist.add (ARDOUR::Properties::layer, 0);
6370 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6371 /* because we set annouce to false, manually add the new region to the
6374 RegionFactory::map_add (nr);
6376 pl->add_region (nr, r->position() + pos);
6379 new_regions.push_front(nr);
6388 RegionFactory::region_name (new_name, r->name());
6390 /* Add the final region */
6393 plist.add (ARDOUR::Properties::start, r->start() + pos);
6394 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6395 plist.add (ARDOUR::Properties::name, new_name);
6396 plist.add (ARDOUR::Properties::layer, 0);
6398 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6399 /* because we set annouce to false, manually add the new region to the
6402 RegionFactory::map_add (nr);
6403 pl->add_region (nr, r->position() + pos);
6406 new_regions.push_front(nr);
6411 /* We might have removed regions, which alters other regions' layering_index,
6412 so we need to do a recursive diff here.
6414 vector<Command*> cmds;
6416 _session->add_commands (cmds);
6418 _session->add_command (new StatefulDiffCommand (pl));
6422 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6423 set_selected_regionview_from_region_list ((*i), Selection::Add);
6429 Editor::place_transient()
6435 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6441 framepos_t where = get_preferred_edit_position();
6443 begin_reversible_command (_("place transient"));
6445 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6446 framepos_t position = (*r)->region()->position();
6447 (*r)->region()->add_transient(where - position);
6450 commit_reversible_command ();
6454 Editor::remove_transient(ArdourCanvas::Item* item)
6460 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6463 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6464 _arv->remove_transient (*(float*) _line->get_data ("position"));
6468 Editor::snap_regions_to_grid ()
6470 list <boost::shared_ptr<Playlist > > used_playlists;
6472 RegionSelection rs = get_regions_from_selection_and_entered ();
6474 if (!_session || rs.empty()) {
6478 begin_reversible_command (_("snap regions to grid"));
6480 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6482 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6484 if (!pl->frozen()) {
6485 /* we haven't seen this playlist before */
6487 /* remember used playlists so we can thaw them later */
6488 used_playlists.push_back(pl);
6492 framepos_t start_frame = (*r)->region()->first_frame ();
6493 snap_to (start_frame);
6494 (*r)->region()->set_position (start_frame);
6497 while (used_playlists.size() > 0) {
6498 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6500 used_playlists.pop_front();
6503 commit_reversible_command ();
6507 Editor::close_region_gaps ()
6509 list <boost::shared_ptr<Playlist > > used_playlists;
6511 RegionSelection rs = get_regions_from_selection_and_entered ();
6513 if (!_session || rs.empty()) {
6517 Dialog dialog (_("Close Region Gaps"));
6520 table.set_spacings (12);
6521 table.set_border_width (12);
6522 Label* l = manage (left_aligned_label (_("Crossfade length")));
6523 table.attach (*l, 0, 1, 0, 1);
6525 SpinButton spin_crossfade (1, 0);
6526 spin_crossfade.set_range (0, 15);
6527 spin_crossfade.set_increments (1, 1);
6528 spin_crossfade.set_value (5);
6529 table.attach (spin_crossfade, 1, 2, 0, 1);
6531 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6533 l = manage (left_aligned_label (_("Pull-back length")));
6534 table.attach (*l, 0, 1, 1, 2);
6536 SpinButton spin_pullback (1, 0);
6537 spin_pullback.set_range (0, 100);
6538 spin_pullback.set_increments (1, 1);
6539 spin_pullback.set_value(30);
6540 table.attach (spin_pullback, 1, 2, 1, 2);
6542 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6544 dialog.get_vbox()->pack_start (table);
6545 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6546 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6549 if (dialog.run () == RESPONSE_CANCEL) {
6553 framepos_t crossfade_len = spin_crossfade.get_value();
6554 framepos_t pull_back_frames = spin_pullback.get_value();
6556 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6557 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6559 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6561 begin_reversible_command (_("close region gaps"));
6564 boost::shared_ptr<Region> last_region;
6566 rs.sort_by_position_and_track();
6568 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6570 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6572 if (!pl->frozen()) {
6573 /* we haven't seen this playlist before */
6575 /* remember used playlists so we can thaw them later */
6576 used_playlists.push_back(pl);
6580 framepos_t position = (*r)->region()->position();
6582 if (idx == 0 || position < last_region->position()){
6583 last_region = (*r)->region();
6588 (*r)->region()->trim_front( (position - pull_back_frames));
6589 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6591 last_region = (*r)->region();
6596 while (used_playlists.size() > 0) {
6597 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6599 used_playlists.pop_front();
6602 commit_reversible_command ();
6606 Editor::tab_to_transient (bool forward)
6608 AnalysisFeatureList positions;
6610 RegionSelection rs = get_regions_from_selection_and_entered ();
6616 framepos_t pos = _session->audible_frame ();
6618 if (!selection->tracks.empty()) {
6620 /* don't waste time searching for transients in duplicate playlists.
6623 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6625 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6627 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6630 boost::shared_ptr<Track> tr = rtv->track();
6632 boost::shared_ptr<Playlist> pl = tr->playlist ();
6634 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6637 positions.push_back (result);
6650 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6651 (*r)->region()->get_transients (positions);
6655 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6658 AnalysisFeatureList::iterator x;
6660 for (x = positions.begin(); x != positions.end(); ++x) {
6666 if (x != positions.end ()) {
6667 _session->request_locate (*x);
6671 AnalysisFeatureList::reverse_iterator x;
6673 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6679 if (x != positions.rend ()) {
6680 _session->request_locate (*x);
6686 Editor::playhead_forward_to_grid ()
6692 framepos_t pos = playhead_cursor->current_frame ();
6693 if (pos < max_framepos - 1) {
6695 snap_to_internal (pos, RoundUpAlways, false);
6696 _session->request_locate (pos);
6702 Editor::playhead_backward_to_grid ()
6708 framepos_t pos = playhead_cursor->current_frame ();
6711 snap_to_internal (pos, RoundDownAlways, false);
6712 _session->request_locate (pos);
6717 Editor::set_track_height (Height h)
6719 TrackSelection& ts (selection->tracks);
6721 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6722 (*x)->set_height_enum (h);
6727 Editor::toggle_tracks_active ()
6729 TrackSelection& ts (selection->tracks);
6731 bool target = false;
6737 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6738 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6742 target = !rtv->_route->active();
6745 rtv->_route->set_active (target, this);
6751 Editor::remove_tracks ()
6753 /* this will delete GUI objects that may be the subject of an event
6754 handler in which this method is called. Defer actual deletion to the
6755 next idle callback, when all event handling is finished.
6757 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
6761 Editor::idle_remove_tracks ()
6764 return false; /* do not call again */
6768 Editor::_remove_tracks ()
6770 TrackSelection& ts (selection->tracks);
6776 vector<string> choices;
6780 const char* trackstr;
6782 vector<boost::shared_ptr<Route> > routes;
6783 bool special_bus = false;
6785 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6786 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6790 if (rtv->is_track()) {
6795 routes.push_back (rtv->_route);
6797 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6802 if (special_bus && !Config->get_allow_special_bus_removal()) {
6803 MessageDialog msg (_("That would be bad news ...."),
6807 msg.set_secondary_text (string_compose (_(
6808 "Removing the master or monitor bus is such a bad idea\n\
6809 that %1 is not going to allow it.\n\
6811 If you really want to do this sort of thing\n\
6812 edit your ardour.rc file to set the\n\
6813 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6820 if (ntracks + nbusses == 0) {
6824 trackstr = P_("track", "tracks", ntracks);
6825 busstr = P_("bus", "busses", nbusses);
6829 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6830 "(You may also lose the playlists associated with the %2)\n\n"
6831 "This action cannot be undone, and the session file will be overwritten!"),
6832 ntracks, trackstr, nbusses, busstr);
6834 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6835 "(You may also lose the playlists associated with the %2)\n\n"
6836 "This action cannot be undone, and the session file will be overwritten!"),
6839 } else if (nbusses) {
6840 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6841 "This action cannot be undone, and the session file will be overwritten"),
6845 choices.push_back (_("No, do nothing."));
6846 if (ntracks + nbusses > 1) {
6847 choices.push_back (_("Yes, remove them."));
6849 choices.push_back (_("Yes, remove it."));
6854 title = string_compose (_("Remove %1"), trackstr);
6856 title = string_compose (_("Remove %1"), busstr);
6859 Choice prompter (title, prompt, choices);
6861 if (prompter.run () != 1) {
6866 Session::StateProtector sp (_session);
6867 DisplaySuspender ds;
6868 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6869 _session->remove_route (*x);
6875 Editor::do_insert_time ()
6877 if (selection->tracks.empty()) {
6881 InsertTimeDialog d (*this);
6882 int response = d.run ();
6884 if (response != RESPONSE_OK) {
6888 if (d.distance() == 0) {
6892 InsertTimeOption opt = d.intersected_region_action ();
6895 get_preferred_edit_position(),
6901 d.move_glued_markers(),
6902 d.move_locked_markers(),
6908 Editor::insert_time (
6909 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6910 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6913 bool commit = false;
6915 if (Config->get_edit_mode() == Lock) {
6919 begin_reversible_command (_("insert time"));
6921 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6923 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6927 /* don't operate on any playlist more than once, which could
6928 * happen if "all playlists" is enabled, but there is more
6929 * than 1 track using playlists "from" a given track.
6932 set<boost::shared_ptr<Playlist> > pl;
6934 if (all_playlists) {
6935 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6937 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6938 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6943 if ((*x)->playlist ()) {
6944 pl.insert ((*x)->playlist ());
6948 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6950 (*i)->clear_changes ();
6951 (*i)->clear_owned_changes ();
6953 if (opt == SplitIntersected) {
6957 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6959 vector<Command*> cmds;
6961 _session->add_commands (cmds);
6963 _session->add_command (new StatefulDiffCommand (*i));
6968 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6970 rtav->route ()->shift (pos, frames);
6978 XMLNode& before (_session->locations()->get_state());
6979 Locations::LocationList copy (_session->locations()->list());
6981 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6983 Locations::LocationList::const_iterator tmp;
6985 bool const was_locked = (*i)->locked ();
6986 if (locked_markers_too) {
6990 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6992 if ((*i)->start() >= pos) {
6993 (*i)->set_start ((*i)->start() + frames);
6994 if (!(*i)->is_mark()) {
6995 (*i)->set_end ((*i)->end() + frames);
7008 XMLNode& after (_session->locations()->get_state());
7009 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7014 _session->tempo_map().insert_time (pos, frames);
7018 commit_reversible_command ();
7023 Editor::fit_selection ()
7025 if (!selection->tracks.empty()) {
7026 fit_tracks (selection->tracks);
7030 /* no selected tracks - use tracks with selected regions */
7032 if (!selection->regions.empty()) {
7033 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7034 tvl.push_back (&(*r)->get_time_axis_view ());
7040 } else if (internal_editing()) {
7041 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7044 if (entered_track) {
7045 tvl.push_back (entered_track);
7054 Editor::fit_tracks (TrackViewList & tracks)
7056 if (tracks.empty()) {
7060 uint32_t child_heights = 0;
7061 int visible_tracks = 0;
7063 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7065 if (!(*t)->marked_for_display()) {
7069 child_heights += (*t)->effective_height() - (*t)->current_height();
7073 /* compute the per-track height from:
7075 total canvas visible height -
7076 height that will be taken by visible children of selected
7077 tracks - height of the ruler/hscroll area
7079 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7080 double first_y_pos = DBL_MAX;
7082 if (h < TimeAxisView::preset_height (HeightSmall)) {
7083 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7084 /* too small to be displayed */
7088 undo_visual_stack.push_back (current_visual_state (true));
7089 PBD::Unwinder<bool> nsv (no_save_visual, true);
7091 /* build a list of all tracks, including children */
7094 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7096 TimeAxisView::Children c = (*i)->get_child_list ();
7097 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7098 all.push_back (j->get());
7103 // find selection range.
7104 // if someone knows how to user TrackViewList::iterator for this
7106 int selected_top = -1;
7107 int selected_bottom = -1;
7109 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7110 if ((*t)->marked_for_display ()) {
7111 if (tracks.contains(*t)) {
7112 if (selected_top == -1) {
7115 selected_bottom = i;
7121 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7122 if ((*t)->marked_for_display ()) {
7123 if (tracks.contains(*t)) {
7124 (*t)->set_height (h);
7125 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7127 if (i > selected_top && i < selected_bottom) {
7128 hide_track_in_display (*t);
7135 set the controls_layout height now, because waiting for its size
7136 request signal handler will cause the vertical adjustment setting to fail
7139 controls_layout.property_height () = _full_canvas_height;
7140 vertical_adjustment.set_value (first_y_pos);
7142 redo_visual_stack.push_back (current_visual_state (true));
7144 visible_tracks_selector.set_text (_("Sel"));
7148 Editor::save_visual_state (uint32_t n)
7150 while (visual_states.size() <= n) {
7151 visual_states.push_back (0);
7154 if (visual_states[n] != 0) {
7155 delete visual_states[n];
7158 visual_states[n] = current_visual_state (true);
7163 Editor::goto_visual_state (uint32_t n)
7165 if (visual_states.size() <= n) {
7169 if (visual_states[n] == 0) {
7173 use_visual_state (*visual_states[n]);
7177 Editor::start_visual_state_op (uint32_t n)
7179 save_visual_state (n);
7181 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7183 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7184 pup->set_text (buf);
7189 Editor::cancel_visual_state_op (uint32_t n)
7191 goto_visual_state (n);
7195 Editor::toggle_region_mute ()
7197 if (_ignore_region_action) {
7201 RegionSelection rs = get_regions_from_selection_and_entered ();
7207 if (rs.size() > 1) {
7208 begin_reversible_command (_("mute regions"));
7210 begin_reversible_command (_("mute region"));
7213 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7215 (*i)->region()->playlist()->clear_changes ();
7216 (*i)->region()->set_muted (!(*i)->region()->muted ());
7217 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7221 commit_reversible_command ();
7225 Editor::combine_regions ()
7227 /* foreach track with selected regions, take all selected regions
7228 and join them into a new region containing the subregions (as a
7232 typedef set<RouteTimeAxisView*> RTVS;
7235 if (selection->regions.empty()) {
7239 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7240 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7243 tracks.insert (rtv);
7247 begin_reversible_command (_("combine regions"));
7249 vector<RegionView*> new_selection;
7251 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7254 if ((rv = (*i)->combine_regions ()) != 0) {
7255 new_selection.push_back (rv);
7259 selection->clear_regions ();
7260 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7261 selection->add (*i);
7264 commit_reversible_command ();
7268 Editor::uncombine_regions ()
7270 typedef set<RouteTimeAxisView*> RTVS;
7273 if (selection->regions.empty()) {
7277 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7278 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7281 tracks.insert (rtv);
7285 begin_reversible_command (_("uncombine regions"));
7287 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7288 (*i)->uncombine_regions ();
7291 commit_reversible_command ();
7295 Editor::toggle_midi_input_active (bool flip_others)
7298 boost::shared_ptr<RouteList> rl (new RouteList);
7300 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7301 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7307 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7310 rl->push_back (rtav->route());
7311 onoff = !mt->input_active();
7315 _session->set_exclusive_input_active (rl, onoff, flip_others);
7322 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7324 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7325 lock_dialog->get_vbox()->pack_start (*padlock);
7327 ArdourButton* b = manage (new ArdourButton);
7328 b->set_name ("lock button");
7329 b->set_text (_("Click to unlock"));
7330 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7331 lock_dialog->get_vbox()->pack_start (*b);
7333 lock_dialog->get_vbox()->show_all ();
7334 lock_dialog->set_size_request (200, 200);
7338 /* The global menu bar continues to be accessible to applications
7339 with modal dialogs, which means that we need to desensitize
7340 all items in the menu bar. Since those items are really just
7341 proxies for actions, that means disabling all actions.
7343 ActionManager::disable_all_actions ();
7345 lock_dialog->present ();
7351 lock_dialog->hide ();
7354 ActionManager::pop_action_state ();
7357 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7358 start_lock_event_timing ();
7363 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7365 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7369 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7371 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7372 Gtkmm2ext::UI::instance()->flush_pending ();
7376 Editor::bring_all_sources_into_session ()
7383 ArdourDialog w (_("Moving embedded files into session folder"));
7384 w.get_vbox()->pack_start (msg);
7387 /* flush all pending GUI events because we're about to start copying
7391 Gtkmm2ext::UI::instance()->flush_pending ();
7395 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));