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::set_session_start_from_playhead ()
2124 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2125 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2127 XMLNode &before = loc->get_state();
2129 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2131 XMLNode &after = loc->get_state();
2133 begin_reversible_command (_("Set session start"));
2135 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2137 commit_reversible_command ();
2142 Editor::set_session_end_from_playhead ()
2148 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2149 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2151 XMLNode &before = loc->get_state();
2153 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2155 XMLNode &after = loc->get_state();
2157 begin_reversible_command (_("Set session start"));
2159 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2161 commit_reversible_command ();
2166 Editor::add_location_from_playhead_cursor ()
2168 add_location_mark (_session->audible_frame());
2172 Editor::remove_location_at_playhead_cursor ()
2177 begin_reversible_command (_("remove marker"));
2179 XMLNode &before = _session->locations()->get_state();
2180 bool removed = false;
2182 //find location(s) at this time
2183 Locations::LocationList locs;
2184 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2185 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2186 if ((*i)->is_mark()) {
2187 _session->locations()->remove (*i);
2194 XMLNode &after = _session->locations()->get_state();
2195 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2197 commit_reversible_command ();
2202 /** Add a range marker around each selected region */
2204 Editor::add_locations_from_region ()
2206 RegionSelection rs = get_regions_from_selection_and_entered ();
2212 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2214 XMLNode &before = _session->locations()->get_state();
2216 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2218 boost::shared_ptr<Region> region = (*i)->region ();
2220 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2222 _session->locations()->add (location, true);
2225 XMLNode &after = _session->locations()->get_state();
2226 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2228 commit_reversible_command ();
2231 /** Add a single range marker around all selected regions */
2233 Editor::add_location_from_region ()
2235 RegionSelection rs = get_regions_from_selection_and_entered ();
2241 begin_reversible_command (_("add marker"));
2243 XMLNode &before = _session->locations()->get_state();
2247 if (rs.size() > 1) {
2248 _session->locations()->next_available_name(markername, "regions");
2250 RegionView* rv = *(rs.begin());
2251 boost::shared_ptr<Region> region = rv->region();
2252 markername = region->name();
2255 if (!choose_new_marker_name(markername)) {
2259 // single range spanning all selected
2260 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2261 _session->locations()->add (location, true);
2263 XMLNode &after = _session->locations()->get_state();
2264 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2266 commit_reversible_command ();
2272 Editor::jump_forward_to_mark ()
2278 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2284 _session->request_locate (pos, _session->transport_rolling());
2288 Editor::jump_backward_to_mark ()
2294 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2300 _session->request_locate (pos, _session->transport_rolling());
2306 framepos_t const pos = _session->audible_frame ();
2309 _session->locations()->next_available_name (markername, "mark");
2311 if (!choose_new_marker_name (markername)) {
2315 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2319 Editor::clear_markers ()
2322 begin_reversible_command (_("clear markers"));
2324 XMLNode &before = _session->locations()->get_state();
2325 _session->locations()->clear_markers ();
2326 XMLNode &after = _session->locations()->get_state();
2327 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2329 commit_reversible_command ();
2334 Editor::clear_ranges ()
2337 begin_reversible_command (_("clear ranges"));
2339 XMLNode &before = _session->locations()->get_state();
2341 _session->locations()->clear_ranges ();
2343 XMLNode &after = _session->locations()->get_state();
2344 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2346 commit_reversible_command ();
2351 Editor::clear_locations ()
2353 begin_reversible_command (_("clear locations"));
2355 XMLNode &before = _session->locations()->get_state();
2356 _session->locations()->clear ();
2357 XMLNode &after = _session->locations()->get_state();
2358 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2360 commit_reversible_command ();
2364 Editor::unhide_markers ()
2366 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2367 Location *l = (*i).first;
2368 if (l->is_hidden() && l->is_mark()) {
2369 l->set_hidden(false, this);
2375 Editor::unhide_ranges ()
2377 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2378 Location *l = (*i).first;
2379 if (l->is_hidden() && l->is_range_marker()) {
2380 l->set_hidden(false, this);
2385 /* INSERT/REPLACE */
2388 Editor::insert_region_list_selection (float times)
2390 RouteTimeAxisView *tv = 0;
2391 boost::shared_ptr<Playlist> playlist;
2393 if (clicked_routeview != 0) {
2394 tv = clicked_routeview;
2395 } else if (!selection->tracks.empty()) {
2396 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2399 } else if (entered_track != 0) {
2400 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2407 if ((playlist = tv->playlist()) == 0) {
2411 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2416 begin_reversible_command (_("insert region"));
2417 playlist->clear_changes ();
2418 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2419 if (Config->get_edit_mode() == Ripple)
2420 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2422 _session->add_command(new StatefulDiffCommand (playlist));
2423 commit_reversible_command ();
2426 /* BUILT-IN EFFECTS */
2429 Editor::reverse_selection ()
2434 /* GAIN ENVELOPE EDITING */
2437 Editor::edit_envelope ()
2444 Editor::transition_to_rolling (bool fwd)
2450 if (_session->config.get_external_sync()) {
2451 switch (Config->get_sync_source()) {
2455 /* transport controlled by the master */
2460 if (_session->is_auditioning()) {
2461 _session->cancel_audition ();
2465 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2469 Editor::play_from_start ()
2471 _session->request_locate (_session->current_start_frame(), true);
2475 Editor::play_from_edit_point ()
2477 _session->request_locate (get_preferred_edit_position(), true);
2481 Editor::play_from_edit_point_and_return ()
2483 framepos_t start_frame;
2484 framepos_t return_frame;
2486 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2488 if (_session->transport_rolling()) {
2489 _session->request_locate (start_frame, false);
2493 /* don't reset the return frame if its already set */
2495 if ((return_frame = _session->requested_return_frame()) < 0) {
2496 return_frame = _session->audible_frame();
2499 if (start_frame >= 0) {
2500 _session->request_roll_at_and_return (start_frame, return_frame);
2505 Editor::play_selection ()
2507 framepos_t start, end;
2508 if (!get_selection_extents ( start, end))
2511 AudioRange ar (start, end, 0);
2512 list<AudioRange> lar;
2515 _session->request_play_range (&lar, true);
2519 Editor::get_preroll ()
2521 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2526 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2528 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2531 location -= get_preroll();
2533 //don't try to locate before the beginning of time
2537 //if follow_playhead is on, keep the playhead on the screen
2538 if ( _follow_playhead )
2539 if ( location < leftmost_frame )
2540 location = leftmost_frame;
2542 _session->request_locate( location );
2546 Editor::play_with_preroll ()
2549 framepos_t preroll = get_preroll();
2551 framepos_t start, end;
2552 if (!get_selection_extents ( start, end))
2555 if (start > preroll)
2556 start = start - preroll;
2558 end = end + preroll; //"post-roll"
2560 AudioRange ar (start, end, 0);
2561 list<AudioRange> lar;
2564 _session->request_play_range (&lar, true);
2569 Editor::play_location (Location& location)
2571 if (location.start() <= location.end()) {
2575 _session->request_bounded_roll (location.start(), location.end());
2579 Editor::loop_location (Location& location)
2581 if (location.start() <= location.end()) {
2587 if ((tll = transport_loop_location()) != 0) {
2588 tll->set (location.start(), location.end());
2590 // enable looping, reposition and start rolling
2591 _session->request_locate (tll->start(), true);
2592 _session->request_play_loop (true);
2597 Editor::do_layer_operation (LayerOperation op)
2599 if (selection->regions.empty ()) {
2603 bool const multiple = selection->regions.size() > 1;
2607 begin_reversible_command (_("raise regions"));
2609 begin_reversible_command (_("raise region"));
2615 begin_reversible_command (_("raise regions to top"));
2617 begin_reversible_command (_("raise region to top"));
2623 begin_reversible_command (_("lower regions"));
2625 begin_reversible_command (_("lower region"));
2631 begin_reversible_command (_("lower regions to bottom"));
2633 begin_reversible_command (_("lower region"));
2638 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2639 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2640 (*i)->clear_owned_changes ();
2643 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2644 boost::shared_ptr<Region> r = (*i)->region ();
2656 r->lower_to_bottom ();
2660 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2661 vector<Command*> cmds;
2663 _session->add_commands (cmds);
2666 commit_reversible_command ();
2670 Editor::raise_region ()
2672 do_layer_operation (Raise);
2676 Editor::raise_region_to_top ()
2678 do_layer_operation (RaiseToTop);
2682 Editor::lower_region ()
2684 do_layer_operation (Lower);
2688 Editor::lower_region_to_bottom ()
2690 do_layer_operation (LowerToBottom);
2693 /** Show the region editor for the selected regions */
2695 Editor::show_region_properties ()
2697 selection->foreach_regionview (&RegionView::show_region_editor);
2700 /** Show the midi list editor for the selected MIDI regions */
2702 Editor::show_midi_list_editor ()
2704 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2708 Editor::rename_region ()
2710 RegionSelection rs = get_regions_from_selection_and_entered ();
2716 ArdourDialog d (*this, _("Rename Region"), true, false);
2718 Label label (_("New name:"));
2721 hbox.set_spacing (6);
2722 hbox.pack_start (label, false, false);
2723 hbox.pack_start (entry, true, true);
2725 d.get_vbox()->set_border_width (12);
2726 d.get_vbox()->pack_start (hbox, false, false);
2728 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2729 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2731 d.set_size_request (300, -1);
2733 entry.set_text (rs.front()->region()->name());
2734 entry.select_region (0, -1);
2736 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2742 int const ret = d.run();
2746 if (ret != RESPONSE_OK) {
2750 std::string str = entry.get_text();
2751 strip_whitespace_edges (str);
2753 rs.front()->region()->set_name (str);
2754 _regions->redisplay ();
2759 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2761 if (_session->is_auditioning()) {
2762 _session->cancel_audition ();
2765 // note: some potential for creativity here, because region doesn't
2766 // have to belong to the playlist that Route is handling
2768 // bool was_soloed = route.soloed();
2770 route.set_solo (true, this);
2772 _session->request_bounded_roll (region->position(), region->position() + region->length());
2774 /* XXX how to unset the solo state ? */
2777 /** Start an audition of the first selected region */
2779 Editor::play_edit_range ()
2781 framepos_t start, end;
2783 if (get_edit_op_range (start, end)) {
2784 _session->request_bounded_roll (start, end);
2789 Editor::play_selected_region ()
2791 framepos_t start = max_framepos;
2794 RegionSelection rs = get_regions_from_selection_and_entered ();
2800 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2801 if ((*i)->region()->position() < start) {
2802 start = (*i)->region()->position();
2804 if ((*i)->region()->last_frame() + 1 > end) {
2805 end = (*i)->region()->last_frame() + 1;
2809 _session->request_bounded_roll (start, end);
2813 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2815 _session->audition_region (region);
2819 Editor::region_from_selection ()
2821 if (clicked_axisview == 0) {
2825 if (selection->time.empty()) {
2829 framepos_t start = selection->time[clicked_selection].start;
2830 framepos_t end = selection->time[clicked_selection].end;
2832 TrackViewList tracks = get_tracks_for_range_action ();
2834 framepos_t selection_cnt = end - start + 1;
2836 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2837 boost::shared_ptr<Region> current;
2838 boost::shared_ptr<Playlist> pl;
2839 framepos_t internal_start;
2842 if ((pl = (*i)->playlist()) == 0) {
2846 if ((current = pl->top_region_at (start)) == 0) {
2850 internal_start = start - current->position();
2851 RegionFactory::region_name (new_name, current->name(), true);
2855 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2856 plist.add (ARDOUR::Properties::length, selection_cnt);
2857 plist.add (ARDOUR::Properties::name, new_name);
2858 plist.add (ARDOUR::Properties::layer, 0);
2860 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2865 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2867 if (selection->time.empty() || selection->tracks.empty()) {
2871 framepos_t start, end;
2872 if (clicked_selection) {
2873 start = selection->time[clicked_selection].start;
2874 end = selection->time[clicked_selection].end;
2876 start = selection->time.start();
2877 end = selection->time.end_frame();
2880 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2881 sort_track_selection (ts);
2883 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2884 boost::shared_ptr<Region> current;
2885 boost::shared_ptr<Playlist> playlist;
2886 framepos_t internal_start;
2889 if ((playlist = (*i)->playlist()) == 0) {
2893 if ((current = playlist->top_region_at(start)) == 0) {
2897 internal_start = start - current->position();
2898 RegionFactory::region_name (new_name, current->name(), true);
2902 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2903 plist.add (ARDOUR::Properties::length, end - start + 1);
2904 plist.add (ARDOUR::Properties::name, new_name);
2906 new_regions.push_back (RegionFactory::create (current, plist));
2911 Editor::split_multichannel_region ()
2913 RegionSelection rs = get_regions_from_selection_and_entered ();
2919 vector< boost::shared_ptr<Region> > v;
2921 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2922 (*x)->region()->separate_by_channel (*_session, v);
2927 Editor::new_region_from_selection ()
2929 region_from_selection ();
2930 cancel_selection ();
2934 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2936 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2937 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2938 case Evoral::OverlapNone:
2946 * - selected tracks, or if there are none...
2947 * - tracks containing selected regions, or if there are none...
2952 Editor::get_tracks_for_range_action () const
2956 if (selection->tracks.empty()) {
2958 /* use tracks with selected regions */
2960 RegionSelection rs = selection->regions;
2962 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2963 TimeAxisView* tv = &(*i)->get_time_axis_view();
2965 if (!t.contains (tv)) {
2971 /* no regions and no tracks: use all tracks */
2977 t = selection->tracks;
2980 return t.filter_to_unique_playlists();
2984 Editor::separate_regions_between (const TimeSelection& ts)
2986 bool in_command = false;
2987 boost::shared_ptr<Playlist> playlist;
2988 RegionSelection new_selection;
2990 TrackViewList tmptracks = get_tracks_for_range_action ();
2991 sort_track_selection (tmptracks);
2993 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2995 RouteTimeAxisView* rtv;
2997 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2999 if (rtv->is_track()) {
3001 /* no edits to destructive tracks */
3003 if (rtv->track()->destructive()) {
3007 if ((playlist = rtv->playlist()) != 0) {
3009 playlist->clear_changes ();
3011 /* XXX need to consider musical time selections here at some point */
3013 double speed = rtv->track()->speed();
3016 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3018 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3019 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3021 latest_regionviews.clear ();
3023 playlist->partition ((framepos_t)((*t).start * speed),
3024 (framepos_t)((*t).end * speed), false);
3028 if (!latest_regionviews.empty()) {
3030 rtv->view()->foreach_regionview (sigc::bind (
3031 sigc::ptr_fun (add_if_covered),
3032 &(*t), &new_selection));
3035 begin_reversible_command (_("separate"));
3039 /* pick up changes to existing regions */
3041 vector<Command*> cmds;
3042 playlist->rdiff (cmds);
3043 _session->add_commands (cmds);
3045 /* pick up changes to the playlist itself (adds/removes)
3048 _session->add_command(new StatefulDiffCommand (playlist));
3057 // selection->set (new_selection);
3059 commit_reversible_command ();
3063 struct PlaylistState {
3064 boost::shared_ptr<Playlist> playlist;
3068 /** Take tracks from get_tracks_for_range_action and cut any regions
3069 * on those tracks so that the tracks are empty over the time
3073 Editor::separate_region_from_selection ()
3075 /* preferentially use *all* ranges in the time selection if we're in range mode
3076 to allow discontiguous operation, since get_edit_op_range() currently
3077 returns a single range.
3080 if (!selection->time.empty()) {
3082 separate_regions_between (selection->time);
3089 if (get_edit_op_range (start, end)) {
3091 AudioRange ar (start, end, 1);
3095 separate_regions_between (ts);
3101 Editor::separate_region_from_punch ()
3103 Location* loc = _session->locations()->auto_punch_location();
3105 separate_regions_using_location (*loc);
3110 Editor::separate_region_from_loop ()
3112 Location* loc = _session->locations()->auto_loop_location();
3114 separate_regions_using_location (*loc);
3119 Editor::separate_regions_using_location (Location& loc)
3121 if (loc.is_mark()) {
3125 AudioRange ar (loc.start(), loc.end(), 1);
3130 separate_regions_between (ts);
3133 /** Separate regions under the selected region */
3135 Editor::separate_under_selected_regions ()
3137 vector<PlaylistState> playlists;
3141 rs = get_regions_from_selection_and_entered();
3143 if (!_session || rs.empty()) {
3147 begin_reversible_command (_("separate region under"));
3149 list<boost::shared_ptr<Region> > regions_to_remove;
3151 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3152 // we can't just remove the region(s) in this loop because
3153 // this removes them from the RegionSelection, and they thus
3154 // disappear from underneath the iterator, and the ++i above
3155 // SEGVs in a puzzling fashion.
3157 // so, first iterate over the regions to be removed from rs and
3158 // add them to the regions_to_remove list, and then
3159 // iterate over the list to actually remove them.
3161 regions_to_remove.push_back ((*i)->region());
3164 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3166 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3169 // is this check necessary?
3173 vector<PlaylistState>::iterator i;
3175 //only take state if this is a new playlist.
3176 for (i = playlists.begin(); i != playlists.end(); ++i) {
3177 if ((*i).playlist == playlist) {
3182 if (i == playlists.end()) {
3184 PlaylistState before;
3185 before.playlist = playlist;
3186 before.before = &playlist->get_state();
3188 playlist->freeze ();
3189 playlists.push_back(before);
3192 //Partition on the region bounds
3193 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3195 //Re-add region that was just removed due to the partition operation
3196 playlist->add_region( (*rl), (*rl)->first_frame() );
3199 vector<PlaylistState>::iterator pl;
3201 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3202 (*pl).playlist->thaw ();
3203 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3206 commit_reversible_command ();
3210 Editor::crop_region_to_selection ()
3212 if (!selection->time.empty()) {
3214 crop_region_to (selection->time.start(), selection->time.end_frame());
3221 if (get_edit_op_range (start, end)) {
3222 crop_region_to (start, end);
3229 Editor::crop_region_to (framepos_t start, framepos_t end)
3231 vector<boost::shared_ptr<Playlist> > playlists;
3232 boost::shared_ptr<Playlist> playlist;
3235 if (selection->tracks.empty()) {
3236 ts = track_views.filter_to_unique_playlists();
3238 ts = selection->tracks.filter_to_unique_playlists ();
3241 sort_track_selection (ts);
3243 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3245 RouteTimeAxisView* rtv;
3247 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3249 boost::shared_ptr<Track> t = rtv->track();
3251 if (t != 0 && ! t->destructive()) {
3253 if ((playlist = rtv->playlist()) != 0) {
3254 playlists.push_back (playlist);
3260 if (playlists.empty()) {
3264 framepos_t the_start;
3268 begin_reversible_command (_("trim to selection"));
3270 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3272 boost::shared_ptr<Region> region;
3276 if ((region = (*i)->top_region_at(the_start)) == 0) {
3280 /* now adjust lengths to that we do the right thing
3281 if the selection extends beyond the region
3284 the_start = max (the_start, (framepos_t) region->position());
3285 if (max_framepos - the_start < region->length()) {
3286 the_end = the_start + region->length() - 1;
3288 the_end = max_framepos;
3290 the_end = min (end, the_end);
3291 cnt = the_end - the_start + 1;
3293 region->clear_changes ();
3294 region->trim_to (the_start, cnt);
3295 _session->add_command (new StatefulDiffCommand (region));
3298 commit_reversible_command ();
3302 Editor::region_fill_track ()
3304 RegionSelection rs = get_regions_from_selection_and_entered ();
3306 if (!_session || rs.empty()) {
3310 framepos_t const end = _session->current_end_frame ();
3312 begin_reversible_command (Operations::region_fill);
3314 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3316 boost::shared_ptr<Region> region ((*i)->region());
3318 boost::shared_ptr<Playlist> pl = region->playlist();
3320 if (end <= region->last_frame()) {
3324 double times = (double) (end - region->last_frame()) / (double) region->length();
3330 pl->clear_changes ();
3331 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3332 _session->add_command (new StatefulDiffCommand (pl));
3335 commit_reversible_command ();
3339 Editor::region_fill_selection ()
3341 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3345 if (selection->time.empty()) {
3349 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3354 framepos_t start = selection->time[clicked_selection].start;
3355 framepos_t end = selection->time[clicked_selection].end;
3357 boost::shared_ptr<Playlist> playlist;
3359 if (selection->tracks.empty()) {
3363 framepos_t selection_length = end - start;
3364 float times = (float)selection_length / region->length();
3366 begin_reversible_command (Operations::fill_selection);
3368 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3370 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3372 if ((playlist = (*i)->playlist()) == 0) {
3376 playlist->clear_changes ();
3377 playlist->add_region (RegionFactory::create (region, true), start, times);
3378 _session->add_command (new StatefulDiffCommand (playlist));
3381 commit_reversible_command ();
3385 Editor::set_region_sync_position ()
3387 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3391 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3393 bool in_command = false;
3395 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3397 if (!(*r)->region()->covers (where)) {
3401 boost::shared_ptr<Region> region ((*r)->region());
3404 begin_reversible_command (_("set sync point"));
3408 region->clear_changes ();
3409 region->set_sync_position (where);
3410 _session->add_command(new StatefulDiffCommand (region));
3414 commit_reversible_command ();
3418 /** Remove the sync positions of the selection */
3420 Editor::remove_region_sync ()
3422 RegionSelection rs = get_regions_from_selection_and_entered ();
3428 begin_reversible_command (_("remove region sync"));
3430 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3432 (*i)->region()->clear_changes ();
3433 (*i)->region()->clear_sync_position ();
3434 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3437 commit_reversible_command ();
3441 Editor::naturalize_region ()
3443 RegionSelection rs = get_regions_from_selection_and_entered ();
3449 if (rs.size() > 1) {
3450 begin_reversible_command (_("move regions to original position"));
3452 begin_reversible_command (_("move region to original position"));
3455 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3456 (*i)->region()->clear_changes ();
3457 (*i)->region()->move_to_natural_position ();
3458 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3461 commit_reversible_command ();
3465 Editor::align_regions (RegionPoint what)
3467 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3473 begin_reversible_command (_("align selection"));
3475 framepos_t const position = get_preferred_edit_position ();
3477 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3478 align_region_internal ((*i)->region(), what, position);
3481 commit_reversible_command ();
3484 struct RegionSortByTime {
3485 bool operator() (const RegionView* a, const RegionView* b) {
3486 return a->region()->position() < b->region()->position();
3491 Editor::align_regions_relative (RegionPoint point)
3493 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3499 framepos_t const position = get_preferred_edit_position ();
3501 framepos_t distance = 0;
3505 list<RegionView*> sorted;
3506 rs.by_position (sorted);
3508 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3513 if (position > r->position()) {
3514 distance = position - r->position();
3516 distance = r->position() - position;
3522 if (position > r->last_frame()) {
3523 distance = position - r->last_frame();
3524 pos = r->position() + distance;
3526 distance = r->last_frame() - position;
3527 pos = r->position() - distance;
3533 pos = r->adjust_to_sync (position);
3534 if (pos > r->position()) {
3535 distance = pos - r->position();
3537 distance = r->position() - pos;
3543 if (pos == r->position()) {
3547 begin_reversible_command (_("align selection (relative)"));
3549 /* move first one specially */
3551 r->clear_changes ();
3552 r->set_position (pos);
3553 _session->add_command(new StatefulDiffCommand (r));
3555 /* move rest by the same amount */
3559 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3561 boost::shared_ptr<Region> region ((*i)->region());
3563 region->clear_changes ();
3566 region->set_position (region->position() + distance);
3568 region->set_position (region->position() - distance);
3571 _session->add_command(new StatefulDiffCommand (region));
3575 commit_reversible_command ();
3579 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3581 begin_reversible_command (_("align region"));
3582 align_region_internal (region, point, position);
3583 commit_reversible_command ();
3587 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3589 region->clear_changes ();
3593 region->set_position (region->adjust_to_sync (position));
3597 if (position > region->length()) {
3598 region->set_position (position - region->length());
3603 region->set_position (position);
3607 _session->add_command(new StatefulDiffCommand (region));
3611 Editor::trim_region_front ()
3617 Editor::trim_region_back ()
3619 trim_region (false);
3623 Editor::trim_region (bool front)
3625 framepos_t where = get_preferred_edit_position();
3626 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3632 begin_reversible_command (front ? _("trim front") : _("trim back"));
3634 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3635 if (!(*i)->region()->locked()) {
3637 (*i)->region()->clear_changes ();
3640 (*i)->region()->trim_front (where);
3641 maybe_locate_with_edit_preroll ( where );
3643 (*i)->region()->trim_end (where);
3644 maybe_locate_with_edit_preroll ( where );
3647 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3651 commit_reversible_command ();
3654 /** Trim the end of the selected regions to the position of the edit cursor */
3656 Editor::trim_region_to_loop ()
3658 Location* loc = _session->locations()->auto_loop_location();
3662 trim_region_to_location (*loc, _("trim to loop"));
3666 Editor::trim_region_to_punch ()
3668 Location* loc = _session->locations()->auto_punch_location();
3672 trim_region_to_location (*loc, _("trim to punch"));
3676 Editor::trim_region_to_location (const Location& loc, const char* str)
3678 RegionSelection rs = get_regions_from_selection_and_entered ();
3680 begin_reversible_command (str);
3682 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3683 RegionView* rv = (*x);
3685 /* require region to span proposed trim */
3686 switch (rv->region()->coverage (loc.start(), loc.end())) {
3687 case Evoral::OverlapInternal:
3693 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3702 if (tav->track() != 0) {
3703 speed = tav->track()->speed();
3706 start = session_frame_to_track_frame (loc.start(), speed);
3707 end = session_frame_to_track_frame (loc.end(), speed);
3709 rv->region()->clear_changes ();
3710 rv->region()->trim_to (start, (end - start));
3711 _session->add_command(new StatefulDiffCommand (rv->region()));
3714 commit_reversible_command ();
3718 Editor::trim_region_to_previous_region_end ()
3720 return trim_to_region(false);
3724 Editor::trim_region_to_next_region_start ()
3726 return trim_to_region(true);
3730 Editor::trim_to_region(bool forward)
3732 RegionSelection rs = get_regions_from_selection_and_entered ();
3734 begin_reversible_command (_("trim to region"));
3736 boost::shared_ptr<Region> next_region;
3738 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3740 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3746 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3754 if (atav->track() != 0) {
3755 speed = atav->track()->speed();
3759 boost::shared_ptr<Region> region = arv->region();
3760 boost::shared_ptr<Playlist> playlist (region->playlist());
3762 region->clear_changes ();
3766 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3772 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3773 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3777 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3783 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3785 arv->region_changed (ARDOUR::bounds_change);
3788 _session->add_command(new StatefulDiffCommand (region));
3791 commit_reversible_command ();
3795 Editor::unfreeze_route ()
3797 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3801 clicked_routeview->track()->unfreeze ();
3805 Editor::_freeze_thread (void* arg)
3807 return static_cast<Editor*>(arg)->freeze_thread ();
3811 Editor::freeze_thread ()
3813 /* create event pool because we may need to talk to the session */
3814 SessionEvent::create_per_thread_pool ("freeze events", 64);
3815 /* create per-thread buffers for process() tree to use */
3816 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3817 current_interthread_info->done = true;
3822 Editor::freeze_route ()
3828 /* stop transport before we start. this is important */
3830 _session->request_transport_speed (0.0);
3832 /* wait for just a little while, because the above call is asynchronous */
3834 Glib::usleep (250000);
3836 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3840 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3842 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3843 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3845 d.set_title (_("Cannot freeze"));
3850 if (clicked_routeview->track()->has_external_redirects()) {
3851 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3852 "Freezing will only process the signal as far as the first send/insert/return."),
3853 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3855 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3856 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3857 d.set_title (_("Freeze Limits"));
3859 int response = d.run ();
3862 case Gtk::RESPONSE_CANCEL:
3869 InterThreadInfo itt;
3870 current_interthread_info = &itt;
3872 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3874 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3876 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3878 while (!itt.done && !itt.cancel) {
3879 gtk_main_iteration ();
3882 current_interthread_info = 0;
3886 Editor::bounce_range_selection (bool replace, bool enable_processing)
3888 if (selection->time.empty()) {
3892 TrackSelection views = selection->tracks;
3894 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3896 if (enable_processing) {
3898 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3900 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3902 _("You can't perform this operation because the processing of the signal "
3903 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3904 "You can do this without processing, which is a different operation.")
3906 d.set_title (_("Cannot bounce"));
3913 framepos_t start = selection->time[clicked_selection].start;
3914 framepos_t end = selection->time[clicked_selection].end;
3915 framepos_t cnt = end - start + 1;
3917 begin_reversible_command (_("bounce range"));
3919 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3921 RouteTimeAxisView* rtv;
3923 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3927 boost::shared_ptr<Playlist> playlist;
3929 if ((playlist = rtv->playlist()) == 0) {
3933 InterThreadInfo itt;
3935 playlist->clear_changes ();
3936 playlist->clear_owned_changes ();
3938 boost::shared_ptr<Region> r;
3940 if (enable_processing) {
3941 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3943 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3951 list<AudioRange> ranges;
3952 ranges.push_back (AudioRange (start, start+cnt, 0));
3953 playlist->cut (ranges); // discard result
3954 playlist->add_region (r, start);
3957 vector<Command*> cmds;
3958 playlist->rdiff (cmds);
3959 _session->add_commands (cmds);
3961 _session->add_command (new StatefulDiffCommand (playlist));
3964 commit_reversible_command ();
3967 /** Delete selected regions, automation points or a time range */
3971 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3972 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3973 bool deleted = false;
3974 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3975 deleted = current_mixer_strip->delete_processors ();
3981 /** Cut selected regions, automation points or a time range */
3988 /** Copy selected regions, automation points or a time range */
3996 /** @return true if a Cut, Copy or Clear is possible */
3998 Editor::can_cut_copy () const
4000 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4007 /** Cut, copy or clear selected regions, automation points or a time range.
4008 * @param op Operation (Delete, Cut, Copy or Clear)
4011 Editor::cut_copy (CutCopyOp op)
4013 /* only cancel selection if cut/copy is successful.*/
4019 opname = _("delete");
4028 opname = _("clear");
4032 /* if we're deleting something, and the mouse is still pressed,
4033 the thing we started a drag for will be gone when we release
4034 the mouse button(s). avoid this. see part 2 at the end of
4038 if (op == Delete || op == Cut || op == Clear) {
4039 if (_drags->active ()) {
4044 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4045 cut_buffer->clear ();
4047 if (entered_marker) {
4049 /* cut/delete op while pointing at a marker */
4052 Location* loc = find_location_from_marker (entered_marker, ignored);
4054 if (_session && loc) {
4055 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4062 switch (mouse_mode) {
4065 begin_reversible_command (opname + ' ' + X_("MIDI"));
4067 commit_reversible_command ();
4073 bool did_edit = false;
4075 if (!selection->regions.empty() || !selection->points.empty()) {
4076 begin_reversible_command (opname + ' ' + _("objects"));
4079 if (!selection->regions.empty()) {
4080 cut_copy_regions (op, selection->regions);
4082 if (op == Cut || op == Delete) {
4083 selection->clear_regions ();
4087 if (!selection->points.empty()) {
4088 cut_copy_points (op);
4090 if (op == Cut || op == Delete) {
4091 selection->clear_points ();
4094 } else if (selection->time.empty()) {
4095 framepos_t start, end;
4096 /* no time selection, see if we can get an edit range
4099 if (get_edit_op_range (start, end)) {
4100 selection->set (start, end);
4102 } else if (!selection->time.empty()) {
4103 begin_reversible_command (opname + ' ' + _("range"));
4106 cut_copy_ranges (op);
4108 if (op == Cut || op == Delete) {
4109 selection->clear_time ();
4114 /* reset repeated paste state */
4117 commit_reversible_command ();
4120 if (op == Delete || op == Cut || op == Clear) {
4125 struct AutomationRecord {
4126 AutomationRecord () : state (0) , line(NULL) {}
4127 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4129 XMLNode* state; ///< state before any operation
4130 const AutomationLine* line; ///< line this came from
4131 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4134 /** Cut, copy or clear selected automation points.
4135 * @param op Operation (Cut, Copy or Clear)
4138 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4140 if (selection->points.empty ()) {
4144 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4145 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4147 /* Keep a record of the AutomationLists that we end up using in this operation */
4148 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4151 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4152 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4153 const AutomationLine& line = (*i)->line();
4154 const boost::shared_ptr<AutomationList> al = line.the_list();
4155 if (lists.find (al) == lists.end ()) {
4156 /* We haven't seen this list yet, so make a record for it. This includes
4157 taking a copy of its current state, in case this is needed for undo later.
4159 lists[al] = AutomationRecord (&al->get_state (), &line);
4163 if (op == Cut || op == Copy) {
4164 /* This operation will involve putting things in the cut buffer, so create an empty
4165 ControlList for each of our source lists to put the cut buffer data in.
4167 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4168 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4171 /* Add all selected points to the relevant copy ControlLists */
4172 framepos_t start = std::numeric_limits<framepos_t>::max();
4173 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4174 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4175 AutomationList::const_iterator j = (*i)->model();
4177 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4179 /* Update earliest MIDI start time in beats */
4180 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4182 /* Update earliest session start time in frames */
4183 start = std::min(start, (*i)->line().session_position(j));
4187 /* Snap start time backwards, so copy/paste is snap aligned. */
4189 if (earliest == Evoral::Beats::max()) {
4190 earliest = Evoral::Beats(); // Weird... don't offset
4192 earliest.round_down_to_beat();
4194 if (start == std::numeric_limits<double>::max()) {
4195 start = 0; // Weird... don't offset
4197 snap_to(start, RoundDownMaybe);
4200 const double line_offset = midi ? earliest.to_double() : start;
4201 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4202 /* Correct this copy list so that it is relative to the earliest
4203 start time, so relative ordering between points is preserved
4204 when copying from several lists and the paste starts at the
4205 earliest copied piece of data. */
4206 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4207 (*j)->when -= line_offset;
4210 /* And add it to the cut buffer */
4211 cut_buffer->add (i->second.copy);
4215 if (op == Delete || op == Cut) {
4216 /* This operation needs to remove things from the main AutomationList, so do that now */
4218 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4219 i->first->freeze ();
4222 /* Remove each selected point from its AutomationList */
4223 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4224 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4225 al->erase ((*i)->model ());
4228 /* Thaw the lists and add undo records for them */
4229 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4230 boost::shared_ptr<AutomationList> al = i->first;
4232 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4237 /** Cut, copy or clear selected automation points.
4238 * @param op Operation (Cut, Copy or Clear)
4241 Editor::cut_copy_midi (CutCopyOp op)
4243 Evoral::Beats earliest = Evoral::Beats::max();
4244 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4245 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4247 if (!mrv->selection().empty()) {
4248 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4250 mrv->cut_copy_clear (op);
4252 /* XXX: not ideal, as there may be more than one track involved in the selection */
4253 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4257 if (!selection->points.empty()) {
4258 cut_copy_points (op, earliest, true);
4259 if (op == Cut || op == Delete) {
4260 selection->clear_points ();
4265 struct lt_playlist {
4266 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4267 return a.playlist < b.playlist;
4271 struct PlaylistMapping {
4273 boost::shared_ptr<Playlist> pl;
4275 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4278 /** Remove `clicked_regionview' */
4280 Editor::remove_clicked_region ()
4282 if (clicked_routeview == 0 || clicked_regionview == 0) {
4286 begin_reversible_command (_("remove region"));
4288 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4290 playlist->clear_changes ();
4291 playlist->clear_owned_changes ();
4292 playlist->remove_region (clicked_regionview->region());
4293 if (Config->get_edit_mode() == Ripple)
4294 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4296 /* We might have removed regions, which alters other regions' layering_index,
4297 so we need to do a recursive diff here.
4299 vector<Command*> cmds;
4300 playlist->rdiff (cmds);
4301 _session->add_commands (cmds);
4303 _session->add_command(new StatefulDiffCommand (playlist));
4304 commit_reversible_command ();
4308 /** Remove the selected regions */
4310 Editor::remove_selected_regions ()
4312 RegionSelection rs = get_regions_from_selection_and_entered ();
4314 if (!_session || rs.empty()) {
4318 begin_reversible_command (_("remove region"));
4320 list<boost::shared_ptr<Region> > regions_to_remove;
4322 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4323 // we can't just remove the region(s) in this loop because
4324 // this removes them from the RegionSelection, and they thus
4325 // disappear from underneath the iterator, and the ++i above
4326 // SEGVs in a puzzling fashion.
4328 // so, first iterate over the regions to be removed from rs and
4329 // add them to the regions_to_remove list, and then
4330 // iterate over the list to actually remove them.
4332 regions_to_remove.push_back ((*i)->region());
4335 vector<boost::shared_ptr<Playlist> > playlists;
4337 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4339 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4342 // is this check necessary?
4346 /* get_regions_from_selection_and_entered() guarantees that
4347 the playlists involved are unique, so there is no need
4351 playlists.push_back (playlist);
4353 playlist->clear_changes ();
4354 playlist->clear_owned_changes ();
4355 playlist->freeze ();
4356 playlist->remove_region (*rl);
4357 if (Config->get_edit_mode() == Ripple)
4358 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4362 vector<boost::shared_ptr<Playlist> >::iterator pl;
4364 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4367 /* We might have removed regions, which alters other regions' layering_index,
4368 so we need to do a recursive diff here.
4370 vector<Command*> cmds;
4371 (*pl)->rdiff (cmds);
4372 _session->add_commands (cmds);
4374 _session->add_command(new StatefulDiffCommand (*pl));
4377 commit_reversible_command ();
4380 /** Cut, copy or clear selected regions.
4381 * @param op Operation (Cut, Copy or Clear)
4384 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4386 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4387 a map when we want ordered access to both elements. i think.
4390 vector<PlaylistMapping> pmap;
4392 framepos_t first_position = max_framepos;
4394 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4395 FreezeList freezelist;
4397 /* get ordering correct before we cut/copy */
4399 rs.sort_by_position_and_track ();
4401 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4403 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4405 if (op == Cut || op == Clear || op == Delete) {
4406 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4409 FreezeList::iterator fl;
4411 // only take state if this is a new playlist.
4412 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4418 if (fl == freezelist.end()) {
4419 pl->clear_changes();
4420 pl->clear_owned_changes ();
4422 freezelist.insert (pl);
4427 TimeAxisView* tv = &(*x)->get_time_axis_view();
4428 vector<PlaylistMapping>::iterator z;
4430 for (z = pmap.begin(); z != pmap.end(); ++z) {
4431 if ((*z).tv == tv) {
4436 if (z == pmap.end()) {
4437 pmap.push_back (PlaylistMapping (tv));
4441 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4443 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4446 /* region not yet associated with a playlist (e.g. unfinished
4453 TimeAxisView& tv = (*x)->get_time_axis_view();
4454 boost::shared_ptr<Playlist> npl;
4455 RegionSelection::iterator tmp;
4462 vector<PlaylistMapping>::iterator z;
4464 for (z = pmap.begin(); z != pmap.end(); ++z) {
4465 if ((*z).tv == &tv) {
4470 assert (z != pmap.end());
4473 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4481 boost::shared_ptr<Region> r = (*x)->region();
4482 boost::shared_ptr<Region> _xx;
4488 pl->remove_region (r);
4489 if (Config->get_edit_mode() == Ripple)
4490 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4494 _xx = RegionFactory::create (r);
4495 npl->add_region (_xx, r->position() - first_position);
4496 pl->remove_region (r);
4497 if (Config->get_edit_mode() == Ripple)
4498 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4502 /* copy region before adding, so we're not putting same object into two different playlists */
4503 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4507 pl->remove_region (r);
4508 if (Config->get_edit_mode() == Ripple)
4509 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4518 list<boost::shared_ptr<Playlist> > foo;
4520 /* the pmap is in the same order as the tracks in which selected regions occured */
4522 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4525 foo.push_back ((*i).pl);
4530 cut_buffer->set (foo);
4534 _last_cut_copy_source_track = 0;
4536 _last_cut_copy_source_track = pmap.front().tv;
4540 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4543 /* We might have removed regions, which alters other regions' layering_index,
4544 so we need to do a recursive diff here.
4546 vector<Command*> cmds;
4547 (*pl)->rdiff (cmds);
4548 _session->add_commands (cmds);
4550 _session->add_command (new StatefulDiffCommand (*pl));
4555 Editor::cut_copy_ranges (CutCopyOp op)
4557 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4559 /* Sort the track selection now, so that it if is used, the playlists
4560 selected by the calls below to cut_copy_clear are in the order that
4561 their tracks appear in the editor. This makes things like paste
4562 of ranges work properly.
4565 sort_track_selection (ts);
4568 if (!entered_track) {
4571 ts.push_back (entered_track);
4574 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4575 (*i)->cut_copy_clear (*selection, op);
4580 Editor::paste (float times, bool from_context)
4582 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4584 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4588 Editor::mouse_paste ()
4593 if (!mouse_frame (where, ignored)) {
4598 paste_internal (where, 1);
4602 Editor::paste_internal (framepos_t position, float times)
4604 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4606 if (cut_buffer->empty(internal_editing())) {
4610 if (position == max_framepos) {
4611 position = get_preferred_edit_position();
4612 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4615 if (position == last_paste_pos) {
4616 /* repeated paste in the same position */
4619 /* paste in new location, reset repeated paste state */
4621 last_paste_pos = position;
4624 /* get everything in the correct order */
4627 if (!selection->tracks.empty()) {
4628 /* If there is a track selection, paste into exactly those tracks and
4629 only those tracks. This allows the user to be explicit and override
4630 the below "do the reasonable thing" logic. */
4631 ts = selection->tracks.filter_to_unique_playlists ();
4632 sort_track_selection (ts);
4634 /* Figure out which track to base the paste at. */
4635 TimeAxisView* base_track = NULL;
4636 if (_edit_point == Editing::EditAtMouse && entered_track) {
4637 /* With the mouse edit point, paste onto the track under the mouse. */
4638 base_track = entered_track;
4639 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4640 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4641 base_track = &entered_regionview->get_time_axis_view();
4642 } else if (_last_cut_copy_source_track) {
4643 /* Paste to the track that the cut/copy came from (see mantis #333). */
4644 base_track = _last_cut_copy_source_track;
4646 /* This is "impossible" since we've copied... well, do nothing. */
4650 /* Walk up to parent if necessary, so base track is a route. */
4651 while (base_track->get_parent()) {
4652 base_track = base_track->get_parent();
4655 /* Add base track and all tracks below it. The paste logic will select
4656 the appropriate object types from the cut buffer in relative order. */
4657 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4658 if ((*i)->order() >= base_track->order()) {
4663 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4664 sort_track_selection (ts);
4666 /* Add automation children of each track in order, for pasting several lines. */
4667 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4668 /* Add any automation children for pasting several lines */
4669 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4674 typedef RouteTimeAxisView::AutomationTracks ATracks;
4675 const ATracks& atracks = rtv->automation_tracks();
4676 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4677 i = ts.insert(i, a->second.get());
4682 /* We now have a list of trackviews starting at base_track, including
4683 automation children, in the order shown in the editor, e.g. R1,
4684 R1.A1, R1.A2, R2, R2.A1, ... */
4687 begin_reversible_command (Operations::paste);
4689 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4690 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4691 /* Only one line copied, and one automation track selected. Do a
4692 "greedy" paste from one automation type to another. */
4694 PasteContext ctx(paste_count, times, ItemCounts(), true);
4695 ts.front()->paste (position, *cut_buffer, ctx);
4699 /* Paste into tracks */
4701 PasteContext ctx(paste_count, times, ItemCounts(), false);
4702 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4703 (*i)->paste (position, *cut_buffer, ctx);
4707 commit_reversible_command ();
4711 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4713 boost::shared_ptr<Playlist> playlist;
4714 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4715 RegionSelection foo;
4717 framepos_t const start_frame = regions.start ();
4718 framepos_t const end_frame = regions.end_frame ();
4720 begin_reversible_command (Operations::duplicate_region);
4722 selection->clear_regions ();
4724 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4726 boost::shared_ptr<Region> r ((*i)->region());
4728 TimeAxisView& tv = (*i)->get_time_axis_view();
4729 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4730 latest_regionviews.clear ();
4731 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4733 playlist = (*i)->region()->playlist();
4734 playlist->clear_changes ();
4735 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4736 _session->add_command(new StatefulDiffCommand (playlist));
4740 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4744 selection->set (foo);
4747 commit_reversible_command ();
4751 Editor::duplicate_selection (float times)
4753 if (selection->time.empty() || selection->tracks.empty()) {
4757 boost::shared_ptr<Playlist> playlist;
4758 vector<boost::shared_ptr<Region> > new_regions;
4759 vector<boost::shared_ptr<Region> >::iterator ri;
4761 create_region_from_selection (new_regions);
4763 if (new_regions.empty()) {
4767 begin_reversible_command (_("duplicate selection"));
4769 ri = new_regions.begin();
4771 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4773 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4774 if ((playlist = (*i)->playlist()) == 0) {
4777 playlist->clear_changes ();
4779 if (clicked_selection) {
4780 end = selection->time[clicked_selection].end;
4782 end = selection->time.end_frame();
4784 playlist->duplicate (*ri, end, times);
4785 _session->add_command (new StatefulDiffCommand (playlist));
4788 if (ri == new_regions.end()) {
4793 commit_reversible_command ();
4796 /** Reset all selected points to the relevant default value */
4798 Editor::reset_point_selection ()
4800 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4801 ARDOUR::AutomationList::iterator j = (*i)->model ();
4802 (*j)->value = (*i)->line().the_list()->default_value ();
4807 Editor::center_playhead ()
4809 float const page = _visible_canvas_width * samples_per_pixel;
4810 center_screen_internal (playhead_cursor->current_frame (), page);
4814 Editor::center_edit_point ()
4816 float const page = _visible_canvas_width * samples_per_pixel;
4817 center_screen_internal (get_preferred_edit_position(), page);
4820 /** Caller must begin and commit a reversible command */
4822 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4824 playlist->clear_changes ();
4826 _session->add_command (new StatefulDiffCommand (playlist));
4830 Editor::nudge_track (bool use_edit, bool forwards)
4832 boost::shared_ptr<Playlist> playlist;
4833 framepos_t distance;
4834 framepos_t next_distance;
4838 start = get_preferred_edit_position();
4843 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4847 if (selection->tracks.empty()) {
4851 begin_reversible_command (_("nudge track"));
4853 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4855 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4857 if ((playlist = (*i)->playlist()) == 0) {
4861 playlist->clear_changes ();
4862 playlist->clear_owned_changes ();
4864 playlist->nudge_after (start, distance, forwards);
4866 vector<Command*> cmds;
4868 playlist->rdiff (cmds);
4869 _session->add_commands (cmds);
4871 _session->add_command (new StatefulDiffCommand (playlist));
4874 commit_reversible_command ();
4878 Editor::remove_last_capture ()
4880 vector<string> choices;
4887 if (Config->get_verify_remove_last_capture()) {
4888 prompt = _("Do you really want to destroy the last capture?"
4889 "\n(This is destructive and cannot be undone)");
4891 choices.push_back (_("No, do nothing."));
4892 choices.push_back (_("Yes, destroy it."));
4894 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4896 if (prompter.run () == 1) {
4897 _session->remove_last_capture ();
4898 _regions->redisplay ();
4902 _session->remove_last_capture();
4903 _regions->redisplay ();
4908 Editor::normalize_region ()
4914 RegionSelection rs = get_regions_from_selection_and_entered ();
4920 NormalizeDialog dialog (rs.size() > 1);
4922 if (dialog.run () == RESPONSE_CANCEL) {
4926 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4929 /* XXX: should really only count audio regions here */
4930 int const regions = rs.size ();
4932 /* Make a list of the selected audio regions' maximum amplitudes, and also
4933 obtain the maximum amplitude of them all.
4935 list<double> max_amps;
4937 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4938 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4940 dialog.descend (1.0 / regions);
4941 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4944 /* the user cancelled the operation */
4948 max_amps.push_back (a);
4949 max_amp = max (max_amp, a);
4954 begin_reversible_command (_("normalize"));
4956 list<double>::const_iterator a = max_amps.begin ();
4958 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4959 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4964 arv->region()->clear_changes ();
4966 double const amp = dialog.normalize_individually() ? *a : max_amp;
4968 arv->audio_region()->normalize (amp, dialog.target ());
4969 _session->add_command (new StatefulDiffCommand (arv->region()));
4974 commit_reversible_command ();
4979 Editor::reset_region_scale_amplitude ()
4985 RegionSelection rs = get_regions_from_selection_and_entered ();
4991 begin_reversible_command ("reset gain");
4993 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4994 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4997 arv->region()->clear_changes ();
4998 arv->audio_region()->set_scale_amplitude (1.0f);
4999 _session->add_command (new StatefulDiffCommand (arv->region()));
5002 commit_reversible_command ();
5006 Editor::adjust_region_gain (bool up)
5008 RegionSelection rs = get_regions_from_selection_and_entered ();
5010 if (!_session || rs.empty()) {
5014 begin_reversible_command ("adjust region gain");
5016 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5017 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5022 arv->region()->clear_changes ();
5024 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5032 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5033 _session->add_command (new StatefulDiffCommand (arv->region()));
5036 commit_reversible_command ();
5041 Editor::reverse_region ()
5047 Reverse rev (*_session);
5048 apply_filter (rev, _("reverse regions"));
5052 Editor::strip_region_silence ()
5058 RegionSelection rs = get_regions_from_selection_and_entered ();
5064 std::list<RegionView*> audio_only;
5066 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5067 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5069 audio_only.push_back (arv);
5073 StripSilenceDialog d (_session, audio_only);
5074 int const r = d.run ();
5078 if (r == Gtk::RESPONSE_OK) {
5079 ARDOUR::AudioIntervalMap silences;
5080 d.silences (silences);
5081 StripSilence s (*_session, silences, d.fade_length());
5082 apply_filter (s, _("strip silence"), &d);
5087 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5089 Evoral::Sequence<Evoral::Beats>::Notes selected;
5090 mrv.selection_as_notelist (selected, true);
5092 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5093 v.push_back (selected);
5095 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5096 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5098 return op (mrv.midi_region()->model(), pos_beats, v);
5102 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5108 begin_reversible_command (op.name ());
5110 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5111 RegionSelection::const_iterator tmp = r;
5114 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5117 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5120 _session->add_command (cmd);
5127 commit_reversible_command ();
5131 Editor::fork_region ()
5133 RegionSelection rs = get_regions_from_selection_and_entered ();
5139 begin_reversible_command (_("Fork Region(s)"));
5141 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5144 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5145 RegionSelection::iterator tmp = r;
5148 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5152 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5153 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5154 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5156 playlist->clear_changes ();
5157 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5158 _session->add_command(new StatefulDiffCommand (playlist));
5160 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5167 commit_reversible_command ();
5171 Editor::quantize_region ()
5174 quantize_regions(get_regions_from_selection_and_entered ());
5179 Editor::quantize_regions (const RegionSelection& rs)
5181 if (rs.n_midi_regions() == 0) {
5185 QuantizeDialog* qd = new QuantizeDialog (*this);
5188 const int r = qd->run ();
5191 if (r == Gtk::RESPONSE_OK) {
5192 Quantize quant (qd->snap_start(), qd->snap_end(),
5193 qd->start_grid_size(), qd->end_grid_size(),
5194 qd->strength(), qd->swing(), qd->threshold());
5196 apply_midi_note_edit_op (quant, rs);
5201 Editor::legatize_region (bool shrink_only)
5204 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5209 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5211 if (rs.n_midi_regions() == 0) {
5215 Legatize legatize(shrink_only);
5216 apply_midi_note_edit_op (legatize, rs);
5220 Editor::transform_region ()
5223 transform_regions(get_regions_from_selection_and_entered ());
5228 Editor::transform_regions (const RegionSelection& rs)
5230 if (rs.n_midi_regions() == 0) {
5234 TransformDialog* td = new TransformDialog();
5237 const int r = td->run();
5240 if (r == Gtk::RESPONSE_OK) {
5241 Transform transform(td->get());
5242 apply_midi_note_edit_op(transform, rs);
5247 Editor::insert_patch_change (bool from_context)
5249 RegionSelection rs = get_regions_from_selection_and_entered ();
5255 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5257 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5258 there may be more than one, but the PatchChangeDialog can only offer
5259 one set of patch menus.
5261 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5263 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5264 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5266 if (d.run() == RESPONSE_CANCEL) {
5270 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5271 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5273 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5274 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5281 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5283 RegionSelection rs = get_regions_from_selection_and_entered ();
5289 begin_reversible_command (command);
5291 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5295 int const N = rs.size ();
5297 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5298 RegionSelection::iterator tmp = r;
5301 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5303 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5306 progress->descend (1.0 / N);
5309 if (arv->audio_region()->apply (filter, progress) == 0) {
5311 playlist->clear_changes ();
5312 playlist->clear_owned_changes ();
5314 if (filter.results.empty ()) {
5316 /* no regions returned; remove the old one */
5317 playlist->remove_region (arv->region ());
5321 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5323 /* first region replaces the old one */
5324 playlist->replace_region (arv->region(), *res, (*res)->position());
5328 while (res != filter.results.end()) {
5329 playlist->add_region (*res, (*res)->position());
5335 /* We might have removed regions, which alters other regions' layering_index,
5336 so we need to do a recursive diff here.
5338 vector<Command*> cmds;
5339 playlist->rdiff (cmds);
5340 _session->add_commands (cmds);
5342 _session->add_command(new StatefulDiffCommand (playlist));
5348 progress->ascend ();
5356 commit_reversible_command ();
5360 Editor::external_edit_region ()
5366 Editor::reset_region_gain_envelopes ()
5368 RegionSelection rs = get_regions_from_selection_and_entered ();
5370 if (!_session || rs.empty()) {
5374 begin_reversible_command (_("reset region gain"));
5376 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5377 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5379 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5380 XMLNode& before (alist->get_state());
5382 arv->audio_region()->set_default_envelope ();
5383 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5387 commit_reversible_command ();
5391 Editor::set_region_gain_visibility (RegionView* rv)
5393 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5395 arv->update_envelope_visibility();
5400 Editor::set_gain_envelope_visibility ()
5406 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5407 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5409 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5415 Editor::toggle_gain_envelope_active ()
5417 if (_ignore_region_action) {
5421 RegionSelection rs = get_regions_from_selection_and_entered ();
5423 if (!_session || rs.empty()) {
5427 begin_reversible_command (_("region gain envelope active"));
5429 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5430 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5432 arv->region()->clear_changes ();
5433 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5434 _session->add_command (new StatefulDiffCommand (arv->region()));
5438 commit_reversible_command ();
5442 Editor::toggle_region_lock ()
5444 if (_ignore_region_action) {
5448 RegionSelection rs = get_regions_from_selection_and_entered ();
5450 if (!_session || rs.empty()) {
5454 begin_reversible_command (_("toggle region lock"));
5456 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5457 (*i)->region()->clear_changes ();
5458 (*i)->region()->set_locked (!(*i)->region()->locked());
5459 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5462 commit_reversible_command ();
5466 Editor::toggle_region_video_lock ()
5468 if (_ignore_region_action) {
5472 RegionSelection rs = get_regions_from_selection_and_entered ();
5474 if (!_session || rs.empty()) {
5478 begin_reversible_command (_("Toggle Video Lock"));
5480 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5481 (*i)->region()->clear_changes ();
5482 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5483 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5486 commit_reversible_command ();
5490 Editor::toggle_region_lock_style ()
5492 if (_ignore_region_action) {
5496 RegionSelection rs = get_regions_from_selection_and_entered ();
5498 if (!_session || rs.empty()) {
5502 begin_reversible_command (_("region lock style"));
5504 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5505 (*i)->region()->clear_changes ();
5506 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5507 (*i)->region()->set_position_lock_style (ns);
5508 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5511 commit_reversible_command ();
5515 Editor::toggle_opaque_region ()
5517 if (_ignore_region_action) {
5521 RegionSelection rs = get_regions_from_selection_and_entered ();
5523 if (!_session || rs.empty()) {
5527 begin_reversible_command (_("change region opacity"));
5529 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5530 (*i)->region()->clear_changes ();
5531 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5532 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5535 commit_reversible_command ();
5539 Editor::toggle_record_enable ()
5541 bool new_state = false;
5543 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5544 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5547 if (!rtav->is_track())
5551 new_state = !rtav->track()->record_enabled();
5555 rtav->track()->set_record_enabled (new_state, this);
5560 Editor::toggle_solo ()
5562 bool new_state = false;
5564 boost::shared_ptr<RouteList> rl (new RouteList);
5566 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5567 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5574 new_state = !rtav->route()->soloed ();
5578 rl->push_back (rtav->route());
5581 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5585 Editor::toggle_mute ()
5587 bool new_state = false;
5589 boost::shared_ptr<RouteList> rl (new RouteList);
5591 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5592 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5599 new_state = !rtav->route()->muted();
5603 rl->push_back (rtav->route());
5606 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5610 Editor::toggle_solo_isolate ()
5616 Editor::fade_range ()
5618 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5620 begin_reversible_command (_("fade range"));
5622 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5623 (*i)->fade_range (selection->time);
5626 commit_reversible_command ();
5631 Editor::set_fade_length (bool in)
5633 RegionSelection rs = get_regions_from_selection_and_entered ();
5639 /* we need a region to measure the offset from the start */
5641 RegionView* rv = rs.front ();
5643 framepos_t pos = get_preferred_edit_position();
5647 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5648 /* edit point is outside the relevant region */
5653 if (pos <= rv->region()->position()) {
5657 len = pos - rv->region()->position();
5658 cmd = _("set fade in length");
5660 if (pos >= rv->region()->last_frame()) {
5664 len = rv->region()->last_frame() - pos;
5665 cmd = _("set fade out length");
5668 begin_reversible_command (cmd);
5670 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5671 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5677 boost::shared_ptr<AutomationList> alist;
5679 alist = tmp->audio_region()->fade_in();
5681 alist = tmp->audio_region()->fade_out();
5684 XMLNode &before = alist->get_state();
5687 tmp->audio_region()->set_fade_in_length (len);
5688 tmp->audio_region()->set_fade_in_active (true);
5690 tmp->audio_region()->set_fade_out_length (len);
5691 tmp->audio_region()->set_fade_out_active (true);
5694 XMLNode &after = alist->get_state();
5695 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5698 commit_reversible_command ();
5702 Editor::set_fade_in_shape (FadeShape shape)
5704 RegionSelection rs = get_regions_from_selection_and_entered ();
5710 begin_reversible_command (_("set fade in shape"));
5712 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5713 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5719 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5720 XMLNode &before = alist->get_state();
5722 tmp->audio_region()->set_fade_in_shape (shape);
5724 XMLNode &after = alist->get_state();
5725 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5728 commit_reversible_command ();
5733 Editor::set_fade_out_shape (FadeShape shape)
5735 RegionSelection rs = get_regions_from_selection_and_entered ();
5741 begin_reversible_command (_("set fade out shape"));
5743 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5744 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5750 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5751 XMLNode &before = alist->get_state();
5753 tmp->audio_region()->set_fade_out_shape (shape);
5755 XMLNode &after = alist->get_state();
5756 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5759 commit_reversible_command ();
5763 Editor::set_fade_in_active (bool yn)
5765 RegionSelection rs = get_regions_from_selection_and_entered ();
5771 begin_reversible_command (_("set fade in active"));
5773 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5774 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5781 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5783 ar->clear_changes ();
5784 ar->set_fade_in_active (yn);
5785 _session->add_command (new StatefulDiffCommand (ar));
5788 commit_reversible_command ();
5792 Editor::set_fade_out_active (bool yn)
5794 RegionSelection rs = get_regions_from_selection_and_entered ();
5800 begin_reversible_command (_("set fade out active"));
5802 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5803 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5809 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5811 ar->clear_changes ();
5812 ar->set_fade_out_active (yn);
5813 _session->add_command(new StatefulDiffCommand (ar));
5816 commit_reversible_command ();
5820 Editor::toggle_region_fades (int dir)
5822 if (_ignore_region_action) {
5826 boost::shared_ptr<AudioRegion> ar;
5829 RegionSelection rs = get_regions_from_selection_and_entered ();
5835 RegionSelection::iterator i;
5836 for (i = rs.begin(); i != rs.end(); ++i) {
5837 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5839 yn = ar->fade_out_active ();
5841 yn = ar->fade_in_active ();
5847 if (i == rs.end()) {
5851 /* XXX should this undo-able? */
5853 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5854 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5857 if (dir == 1 || dir == 0) {
5858 ar->set_fade_in_active (!yn);
5861 if (dir == -1 || dir == 0) {
5862 ar->set_fade_out_active (!yn);
5868 /** Update region fade visibility after its configuration has been changed */
5870 Editor::update_region_fade_visibility ()
5872 bool _fade_visibility = _session->config.get_show_region_fades ();
5874 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5875 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5877 if (_fade_visibility) {
5878 v->audio_view()->show_all_fades ();
5880 v->audio_view()->hide_all_fades ();
5887 Editor::set_edit_point ()
5892 if (!mouse_frame (where, ignored)) {
5898 if (selection->markers.empty()) {
5900 mouse_add_new_marker (where);
5905 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5908 loc->move_to (where);
5914 Editor::set_playhead_cursor ()
5916 if (entered_marker) {
5917 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5922 if (!mouse_frame (where, ignored)) {
5929 _session->request_locate (where, _session->transport_rolling());
5933 if (ARDOUR_UI::config()->get_follow_edits()) {
5934 cancel_time_selection();
5939 Editor::split_region ()
5941 //if a range is selected, separate it
5942 if ( !selection->time.empty()) {
5943 separate_regions_between (selection->time);
5947 //if no range was selected, try to find some regions to split
5948 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
5950 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5952 framepos_t where = get_preferred_edit_position ();
5958 split_regions_at (where, rs);
5962 struct EditorOrderRouteSorter {
5963 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5964 return a->order_key () < b->order_key ();
5969 Editor::select_next_route()
5971 if (selection->tracks.empty()) {
5972 selection->set (track_views.front());
5976 TimeAxisView* current = selection->tracks.front();
5980 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5981 if (*i == current) {
5983 if (i != track_views.end()) {
5986 current = (*(track_views.begin()));
5987 //selection->set (*(track_views.begin()));
5992 rui = dynamic_cast<RouteUI *>(current);
5993 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5995 selection->set(current);
5997 ensure_time_axis_view_is_visible (*current, false);
6001 Editor::select_prev_route()
6003 if (selection->tracks.empty()) {
6004 selection->set (track_views.front());
6008 TimeAxisView* current = selection->tracks.front();
6012 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6013 if (*i == current) {
6015 if (i != track_views.rend()) {
6018 current = *(track_views.rbegin());
6023 rui = dynamic_cast<RouteUI *>(current);
6024 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6026 selection->set (current);
6028 ensure_time_axis_view_is_visible (*current, false);
6032 Editor::set_loop_from_selection (bool play)
6034 if (_session == 0) {
6038 framepos_t start, end;
6039 if (!get_selection_extents ( start, end))
6042 set_loop_range (start, end, _("set loop range from selection"));
6045 _session->request_play_loop (true, true);
6050 Editor::set_loop_from_region (bool play)
6052 framepos_t start, end;
6053 if (!get_selection_extents ( start, end))
6056 set_loop_range (start, end, _("set loop range from region"));
6059 _session->request_locate (start, true);
6060 _session->request_play_loop (true);
6065 Editor::set_punch_from_selection ()
6067 if (_session == 0) {
6071 framepos_t start, end;
6072 if (!get_selection_extents ( start, end))
6075 set_punch_range (start, end, _("set punch range from selection"));
6079 Editor::set_session_extents_from_selection ()
6081 if (_session == 0) {
6085 framepos_t start, end;
6086 if (!get_selection_extents ( start, end))
6090 if ((loc = _session->locations()->session_range_location()) == 0) {
6091 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6093 XMLNode &before = loc->get_state();
6095 _session->set_session_extents ( start, end );
6097 XMLNode &after = loc->get_state();
6099 begin_reversible_command (_("set session start/end from selection"));
6101 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6103 commit_reversible_command ();
6108 Editor::set_punch_from_region ()
6110 framepos_t start, end;
6111 if (!get_selection_extents ( start, end))
6114 set_punch_range (start, end, _("set punch range from region"));
6118 Editor::pitch_shift_region ()
6120 RegionSelection rs = get_regions_from_selection_and_entered ();
6122 RegionSelection audio_rs;
6123 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6124 if (dynamic_cast<AudioRegionView*> (*i)) {
6125 audio_rs.push_back (*i);
6129 if (audio_rs.empty()) {
6133 pitch_shift (audio_rs, 1.2);
6137 Editor::transpose_region ()
6139 RegionSelection rs = get_regions_from_selection_and_entered ();
6141 list<MidiRegionView*> midi_region_views;
6142 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6143 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6145 midi_region_views.push_back (mrv);
6150 int const r = d.run ();
6151 if (r != RESPONSE_ACCEPT) {
6155 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6156 (*i)->midi_region()->transpose (d.semitones ());
6161 Editor::set_tempo_from_region ()
6163 RegionSelection rs = get_regions_from_selection_and_entered ();
6165 if (!_session || rs.empty()) {
6169 RegionView* rv = rs.front();
6171 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6175 Editor::use_range_as_bar ()
6177 framepos_t start, end;
6178 if (get_edit_op_range (start, end)) {
6179 define_one_bar (start, end);
6184 Editor::define_one_bar (framepos_t start, framepos_t end)
6186 framepos_t length = end - start;
6188 const Meter& m (_session->tempo_map().meter_at (start));
6190 /* length = 1 bar */
6192 /* now we want frames per beat.
6193 we have frames per bar, and beats per bar, so ...
6196 /* XXXX METER MATH */
6198 double frames_per_beat = length / m.divisions_per_bar();
6200 /* beats per minute = */
6202 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6204 /* now decide whether to:
6206 (a) set global tempo
6207 (b) add a new tempo marker
6211 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6213 bool do_global = false;
6215 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6217 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6218 at the start, or create a new marker
6221 vector<string> options;
6222 options.push_back (_("Cancel"));
6223 options.push_back (_("Add new marker"));
6224 options.push_back (_("Set global tempo"));
6227 _("Define one bar"),
6228 _("Do you want to set the global tempo or add a new tempo marker?"),
6232 c.set_default_response (2);
6248 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6249 if the marker is at the region starter, change it, otherwise add
6254 begin_reversible_command (_("set tempo from region"));
6255 XMLNode& before (_session->tempo_map().get_state());
6258 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6259 } else if (t.frame() == start) {
6260 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6262 Timecode::BBT_Time bbt;
6263 _session->tempo_map().bbt_time (start, bbt);
6264 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6267 XMLNode& after (_session->tempo_map().get_state());
6269 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6270 commit_reversible_command ();
6274 Editor::split_region_at_transients ()
6276 AnalysisFeatureList positions;
6278 RegionSelection rs = get_regions_from_selection_and_entered ();
6280 if (!_session || rs.empty()) {
6284 begin_reversible_command (_("split regions"));
6286 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6288 RegionSelection::iterator tmp;
6293 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6295 if (ar && (ar->get_transients (positions) == 0)) {
6296 split_region_at_points ((*i)->region(), positions, true);
6303 commit_reversible_command ();
6308 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6310 bool use_rhythmic_rodent = false;
6312 boost::shared_ptr<Playlist> pl = r->playlist();
6314 list<boost::shared_ptr<Region> > new_regions;
6320 if (positions.empty()) {
6325 if (positions.size() > 20 && can_ferret) {
6326 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);
6327 MessageDialog msg (msgstr,
6330 Gtk::BUTTONS_OK_CANCEL);
6333 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6334 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6336 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6339 msg.set_title (_("Excessive split?"));
6342 int response = msg.run();
6348 case RESPONSE_APPLY:
6349 use_rhythmic_rodent = true;
6356 if (use_rhythmic_rodent) {
6357 show_rhythm_ferret ();
6361 AnalysisFeatureList::const_iterator x;
6363 pl->clear_changes ();
6364 pl->clear_owned_changes ();
6366 x = positions.begin();
6368 if (x == positions.end()) {
6373 pl->remove_region (r);
6377 while (x != positions.end()) {
6379 /* deal with positons that are out of scope of present region bounds */
6380 if (*x <= 0 || *x > r->length()) {
6385 /* file start = original start + how far we from the initial position ?
6388 framepos_t file_start = r->start() + pos;
6390 /* length = next position - current position
6393 framepos_t len = (*x) - pos;
6395 /* XXX we do we really want to allow even single-sample regions?
6396 shouldn't we have some kind of lower limit on region size?
6405 if (RegionFactory::region_name (new_name, r->name())) {
6409 /* do NOT announce new regions 1 by one, just wait till they are all done */
6413 plist.add (ARDOUR::Properties::start, file_start);
6414 plist.add (ARDOUR::Properties::length, len);
6415 plist.add (ARDOUR::Properties::name, new_name);
6416 plist.add (ARDOUR::Properties::layer, 0);
6418 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6419 /* because we set annouce to false, manually add the new region to the
6422 RegionFactory::map_add (nr);
6424 pl->add_region (nr, r->position() + pos);
6427 new_regions.push_front(nr);
6436 RegionFactory::region_name (new_name, r->name());
6438 /* Add the final region */
6441 plist.add (ARDOUR::Properties::start, r->start() + pos);
6442 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6443 plist.add (ARDOUR::Properties::name, new_name);
6444 plist.add (ARDOUR::Properties::layer, 0);
6446 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6447 /* because we set annouce to false, manually add the new region to the
6450 RegionFactory::map_add (nr);
6451 pl->add_region (nr, r->position() + pos);
6454 new_regions.push_front(nr);
6459 /* We might have removed regions, which alters other regions' layering_index,
6460 so we need to do a recursive diff here.
6462 vector<Command*> cmds;
6464 _session->add_commands (cmds);
6466 _session->add_command (new StatefulDiffCommand (pl));
6470 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6471 set_selected_regionview_from_region_list ((*i), Selection::Add);
6477 Editor::place_transient()
6483 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6489 framepos_t where = get_preferred_edit_position();
6491 begin_reversible_command (_("place transient"));
6493 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6494 framepos_t position = (*r)->region()->position();
6495 (*r)->region()->add_transient(where - position);
6498 commit_reversible_command ();
6502 Editor::remove_transient(ArdourCanvas::Item* item)
6508 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6511 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6512 _arv->remove_transient (*(float*) _line->get_data ("position"));
6516 Editor::snap_regions_to_grid ()
6518 list <boost::shared_ptr<Playlist > > used_playlists;
6520 RegionSelection rs = get_regions_from_selection_and_entered ();
6522 if (!_session || rs.empty()) {
6526 begin_reversible_command (_("snap regions to grid"));
6528 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6530 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6532 if (!pl->frozen()) {
6533 /* we haven't seen this playlist before */
6535 /* remember used playlists so we can thaw them later */
6536 used_playlists.push_back(pl);
6540 framepos_t start_frame = (*r)->region()->first_frame ();
6541 snap_to (start_frame);
6542 (*r)->region()->set_position (start_frame);
6545 while (used_playlists.size() > 0) {
6546 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6548 used_playlists.pop_front();
6551 commit_reversible_command ();
6555 Editor::close_region_gaps ()
6557 list <boost::shared_ptr<Playlist > > used_playlists;
6559 RegionSelection rs = get_regions_from_selection_and_entered ();
6561 if (!_session || rs.empty()) {
6565 Dialog dialog (_("Close Region Gaps"));
6568 table.set_spacings (12);
6569 table.set_border_width (12);
6570 Label* l = manage (left_aligned_label (_("Crossfade length")));
6571 table.attach (*l, 0, 1, 0, 1);
6573 SpinButton spin_crossfade (1, 0);
6574 spin_crossfade.set_range (0, 15);
6575 spin_crossfade.set_increments (1, 1);
6576 spin_crossfade.set_value (5);
6577 table.attach (spin_crossfade, 1, 2, 0, 1);
6579 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6581 l = manage (left_aligned_label (_("Pull-back length")));
6582 table.attach (*l, 0, 1, 1, 2);
6584 SpinButton spin_pullback (1, 0);
6585 spin_pullback.set_range (0, 100);
6586 spin_pullback.set_increments (1, 1);
6587 spin_pullback.set_value(30);
6588 table.attach (spin_pullback, 1, 2, 1, 2);
6590 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6592 dialog.get_vbox()->pack_start (table);
6593 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6594 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6597 if (dialog.run () == RESPONSE_CANCEL) {
6601 framepos_t crossfade_len = spin_crossfade.get_value();
6602 framepos_t pull_back_frames = spin_pullback.get_value();
6604 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6605 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6607 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6609 begin_reversible_command (_("close region gaps"));
6612 boost::shared_ptr<Region> last_region;
6614 rs.sort_by_position_and_track();
6616 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6618 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6620 if (!pl->frozen()) {
6621 /* we haven't seen this playlist before */
6623 /* remember used playlists so we can thaw them later */
6624 used_playlists.push_back(pl);
6628 framepos_t position = (*r)->region()->position();
6630 if (idx == 0 || position < last_region->position()){
6631 last_region = (*r)->region();
6636 (*r)->region()->trim_front( (position - pull_back_frames));
6637 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6639 last_region = (*r)->region();
6644 while (used_playlists.size() > 0) {
6645 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6647 used_playlists.pop_front();
6650 commit_reversible_command ();
6654 Editor::tab_to_transient (bool forward)
6656 AnalysisFeatureList positions;
6658 RegionSelection rs = get_regions_from_selection_and_entered ();
6664 framepos_t pos = _session->audible_frame ();
6666 if (!selection->tracks.empty()) {
6668 /* don't waste time searching for transients in duplicate playlists.
6671 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6673 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6675 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6678 boost::shared_ptr<Track> tr = rtv->track();
6680 boost::shared_ptr<Playlist> pl = tr->playlist ();
6682 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6685 positions.push_back (result);
6698 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6699 (*r)->region()->get_transients (positions);
6703 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6706 AnalysisFeatureList::iterator x;
6708 for (x = positions.begin(); x != positions.end(); ++x) {
6714 if (x != positions.end ()) {
6715 _session->request_locate (*x);
6719 AnalysisFeatureList::reverse_iterator x;
6721 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6727 if (x != positions.rend ()) {
6728 _session->request_locate (*x);
6734 Editor::playhead_forward_to_grid ()
6740 framepos_t pos = playhead_cursor->current_frame ();
6741 if (pos < max_framepos - 1) {
6743 snap_to_internal (pos, RoundUpAlways, false);
6744 _session->request_locate (pos);
6750 Editor::playhead_backward_to_grid ()
6756 framepos_t pos = playhead_cursor->current_frame ();
6759 snap_to_internal (pos, RoundDownAlways, false);
6760 _session->request_locate (pos);
6765 Editor::set_track_height (Height h)
6767 TrackSelection& ts (selection->tracks);
6769 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6770 (*x)->set_height_enum (h);
6775 Editor::toggle_tracks_active ()
6777 TrackSelection& ts (selection->tracks);
6779 bool target = false;
6785 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6786 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6790 target = !rtv->_route->active();
6793 rtv->_route->set_active (target, this);
6799 Editor::remove_tracks ()
6801 /* this will delete GUI objects that may be the subject of an event
6802 handler in which this method is called. Defer actual deletion to the
6803 next idle callback, when all event handling is finished.
6805 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
6809 Editor::idle_remove_tracks ()
6812 return false; /* do not call again */
6816 Editor::_remove_tracks ()
6818 TrackSelection& ts (selection->tracks);
6824 vector<string> choices;
6828 const char* trackstr;
6830 vector<boost::shared_ptr<Route> > routes;
6831 bool special_bus = false;
6833 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6834 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6838 if (rtv->is_track()) {
6843 routes.push_back (rtv->_route);
6845 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6850 if (special_bus && !Config->get_allow_special_bus_removal()) {
6851 MessageDialog msg (_("That would be bad news ...."),
6855 msg.set_secondary_text (string_compose (_(
6856 "Removing the master or monitor bus is such a bad idea\n\
6857 that %1 is not going to allow it.\n\
6859 If you really want to do this sort of thing\n\
6860 edit your ardour.rc file to set the\n\
6861 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6868 if (ntracks + nbusses == 0) {
6872 trackstr = P_("track", "tracks", ntracks);
6873 busstr = P_("bus", "busses", nbusses);
6877 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6878 "(You may also lose the playlists associated with the %2)\n\n"
6879 "This action cannot be undone, and the session file will be overwritten!"),
6880 ntracks, trackstr, nbusses, busstr);
6882 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6883 "(You may also lose the playlists associated with the %2)\n\n"
6884 "This action cannot be undone, and the session file will be overwritten!"),
6887 } else if (nbusses) {
6888 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6889 "This action cannot be undone, and the session file will be overwritten"),
6893 choices.push_back (_("No, do nothing."));
6894 if (ntracks + nbusses > 1) {
6895 choices.push_back (_("Yes, remove them."));
6897 choices.push_back (_("Yes, remove it."));
6902 title = string_compose (_("Remove %1"), trackstr);
6904 title = string_compose (_("Remove %1"), busstr);
6907 Choice prompter (title, prompt, choices);
6909 if (prompter.run () != 1) {
6914 Session::StateProtector sp (_session);
6915 DisplaySuspender ds;
6916 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6917 _session->remove_route (*x);
6923 Editor::do_insert_time ()
6925 if (selection->tracks.empty()) {
6929 InsertTimeDialog d (*this);
6930 int response = d.run ();
6932 if (response != RESPONSE_OK) {
6936 if (d.distance() == 0) {
6940 InsertTimeOption opt = d.intersected_region_action ();
6943 get_preferred_edit_position(),
6949 d.move_glued_markers(),
6950 d.move_locked_markers(),
6956 Editor::insert_time (
6957 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6958 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6961 bool commit = false;
6963 if (Config->get_edit_mode() == Lock) {
6967 begin_reversible_command (_("insert time"));
6969 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6971 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6975 /* don't operate on any playlist more than once, which could
6976 * happen if "all playlists" is enabled, but there is more
6977 * than 1 track using playlists "from" a given track.
6980 set<boost::shared_ptr<Playlist> > pl;
6982 if (all_playlists) {
6983 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6985 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6986 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6991 if ((*x)->playlist ()) {
6992 pl.insert ((*x)->playlist ());
6996 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6998 (*i)->clear_changes ();
6999 (*i)->clear_owned_changes ();
7001 if (opt == SplitIntersected) {
7005 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7007 vector<Command*> cmds;
7009 _session->add_commands (cmds);
7011 _session->add_command (new StatefulDiffCommand (*i));
7016 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7018 rtav->route ()->shift (pos, frames);
7026 XMLNode& before (_session->locations()->get_state());
7027 Locations::LocationList copy (_session->locations()->list());
7029 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7031 Locations::LocationList::const_iterator tmp;
7033 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7034 bool const was_locked = (*i)->locked ();
7035 if (locked_markers_too) {
7039 if ((*i)->start() >= pos) {
7040 // move end first, in case we're moving by more than the length of the range
7041 if (!(*i)->is_mark()) {
7042 (*i)->set_end ((*i)->end() + frames);
7044 (*i)->set_start ((*i)->start() + frames);
7055 XMLNode& after (_session->locations()->get_state());
7056 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7061 _session->tempo_map().insert_time (pos, frames);
7065 commit_reversible_command ();
7069 Editor::do_cut_time ()
7071 if (selection->tracks.empty()) {
7075 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7076 ArdourDialog d (*this, _("Cut Time"));
7077 VButtonBox button_box;
7080 CheckButton glue_button (_("Move Glued Regions")); glue_button.set_active();
7081 CheckButton marker_button (_("Move Markers")); marker_button.set_active();
7082 CheckButton tempo_button (_("Move Tempo & Meters")); tempo_button.set_active();
7083 AudioClock clock ("cutTimeClock", true, "", true, false, true, false);
7087 clock.set_session (_session);
7088 clock.set_bbt_reference (pos);
7090 clock_box.pack_start (clock, false, true);
7092 option_box.set_spacing (6);
7093 option_box.pack_start (button_box, false, false);
7094 option_box.pack_start (glue_button, false, false);
7095 option_box.pack_start (marker_button, false, false);
7096 option_box.pack_start (tempo_button, false, false);
7098 d.get_vbox()->set_border_width (12);
7099 d.get_vbox()->pack_start (clock_box, false, false);
7100 d.get_vbox()->pack_start (option_box, false, false);
7104 glue_button.show ();
7107 marker_button.show ();
7108 tempo_button.show ();
7110 d.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
7111 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
7114 int response = d.run ();
7116 if (response != RESPONSE_OK) {
7120 framecnt_t distance = clock.current_duration (pos);
7122 if (distance == 0) {
7126 cut_time (pos, distance, SplitIntersected, glue_button.get_active(), marker_button.get_active(), tempo_button.get_active());
7130 Editor::cut_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7131 bool ignore_music_glue, bool markers_too, bool tempo_too)
7133 bool commit = false;
7135 if (Config->get_edit_mode() == Lock) {
7136 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7140 begin_reversible_command (_("cut time"));
7142 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7144 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7148 XMLNode &before = pl->get_state();
7150 std::list<AudioRange> rl;
7151 AudioRange ar(pos, pos+frames, 0);
7154 pl->shift (pos, -frames, true, ignore_music_glue);
7156 XMLNode &after = pl->get_state();
7158 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7163 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7165 rtav->route ()->shift (pos, -frames);
7170 std::list<Location*> loc_kill_list;
7175 XMLNode& before (_session->locations()->get_state());
7176 Locations::LocationList copy (_session->locations()->list());
7178 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7180 if (!(*i)->is_mark()) { //range; have to handle both start and end
7181 if ((*i)->end() >= pos
7182 && (*i)->end() < pos+frames
7183 && (*i)->start() >= pos
7184 && (*i)->end() < pos+frames) { //range is completely enclosed; kill it
7186 loc_kill_list.push_back(*i);
7187 } else { //ony start or end is included, try to do the right thing
7188 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7189 (*i)->set_end (pos); //bring the end to the cut
7191 } else if ((*i)->end() >= pos) {
7192 (*i)->set_end ((*i)->end()-frames); //slip the end marker back
7195 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7196 (*i)->set_start (pos); //bring the start marker to the beginning of the cut
7198 } else if ((*i)->start() >= pos) {
7199 (*i)->set_start ((*i)->start() -frames); //slip the end marker back
7203 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7204 loc_kill_list.push_back(*i);
7206 } else if ((*i)->start() >= pos) {
7207 (*i)->set_start ((*i)->start() -frames);
7212 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7213 _session->locations()->remove( *i );
7217 XMLNode& after (_session->locations()->get_state());
7218 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7224 XMLNode& before (_session->tempo_map().get_state());
7226 if (_session->tempo_map().cut_time (pos, frames) ) {
7227 XMLNode& after (_session->tempo_map().get_state());
7228 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7234 commit_reversible_command ();
7239 Editor::fit_selection ()
7241 if (!selection->tracks.empty()) {
7242 fit_tracks (selection->tracks);
7246 /* no selected tracks - use tracks with selected regions */
7248 if (!selection->regions.empty()) {
7249 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7250 tvl.push_back (&(*r)->get_time_axis_view ());
7256 } else if (internal_editing()) {
7257 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7260 if (entered_track) {
7261 tvl.push_back (entered_track);
7270 Editor::fit_tracks (TrackViewList & tracks)
7272 if (tracks.empty()) {
7276 uint32_t child_heights = 0;
7277 int visible_tracks = 0;
7279 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7281 if (!(*t)->marked_for_display()) {
7285 child_heights += (*t)->effective_height() - (*t)->current_height();
7289 /* compute the per-track height from:
7291 total canvas visible height -
7292 height that will be taken by visible children of selected
7293 tracks - height of the ruler/hscroll area
7295 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7296 double first_y_pos = DBL_MAX;
7298 if (h < TimeAxisView::preset_height (HeightSmall)) {
7299 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7300 /* too small to be displayed */
7304 undo_visual_stack.push_back (current_visual_state (true));
7305 PBD::Unwinder<bool> nsv (no_save_visual, true);
7307 /* build a list of all tracks, including children */
7310 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7312 TimeAxisView::Children c = (*i)->get_child_list ();
7313 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7314 all.push_back (j->get());
7319 // find selection range.
7320 // if someone knows how to user TrackViewList::iterator for this
7322 int selected_top = -1;
7323 int selected_bottom = -1;
7325 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7326 if ((*t)->marked_for_display ()) {
7327 if (tracks.contains(*t)) {
7328 if (selected_top == -1) {
7331 selected_bottom = i;
7337 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7338 if ((*t)->marked_for_display ()) {
7339 if (tracks.contains(*t)) {
7340 (*t)->set_height (h);
7341 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7343 if (i > selected_top && i < selected_bottom) {
7344 hide_track_in_display (*t);
7351 set the controls_layout height now, because waiting for its size
7352 request signal handler will cause the vertical adjustment setting to fail
7355 controls_layout.property_height () = _full_canvas_height;
7356 vertical_adjustment.set_value (first_y_pos);
7358 redo_visual_stack.push_back (current_visual_state (true));
7360 visible_tracks_selector.set_text (_("Sel"));
7364 Editor::save_visual_state (uint32_t n)
7366 while (visual_states.size() <= n) {
7367 visual_states.push_back (0);
7370 if (visual_states[n] != 0) {
7371 delete visual_states[n];
7374 visual_states[n] = current_visual_state (true);
7379 Editor::goto_visual_state (uint32_t n)
7381 if (visual_states.size() <= n) {
7385 if (visual_states[n] == 0) {
7389 use_visual_state (*visual_states[n]);
7393 Editor::start_visual_state_op (uint32_t n)
7395 save_visual_state (n);
7397 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7399 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7400 pup->set_text (buf);
7405 Editor::cancel_visual_state_op (uint32_t n)
7407 goto_visual_state (n);
7411 Editor::toggle_region_mute ()
7413 if (_ignore_region_action) {
7417 RegionSelection rs = get_regions_from_selection_and_entered ();
7423 if (rs.size() > 1) {
7424 begin_reversible_command (_("mute regions"));
7426 begin_reversible_command (_("mute region"));
7429 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7431 (*i)->region()->playlist()->clear_changes ();
7432 (*i)->region()->set_muted (!(*i)->region()->muted ());
7433 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7437 commit_reversible_command ();
7441 Editor::combine_regions ()
7443 /* foreach track with selected regions, take all selected regions
7444 and join them into a new region containing the subregions (as a
7448 typedef set<RouteTimeAxisView*> RTVS;
7451 if (selection->regions.empty()) {
7455 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7456 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7459 tracks.insert (rtv);
7463 begin_reversible_command (_("combine regions"));
7465 vector<RegionView*> new_selection;
7467 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7470 if ((rv = (*i)->combine_regions ()) != 0) {
7471 new_selection.push_back (rv);
7475 selection->clear_regions ();
7476 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7477 selection->add (*i);
7480 commit_reversible_command ();
7484 Editor::uncombine_regions ()
7486 typedef set<RouteTimeAxisView*> RTVS;
7489 if (selection->regions.empty()) {
7493 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7494 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7497 tracks.insert (rtv);
7501 begin_reversible_command (_("uncombine regions"));
7503 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7504 (*i)->uncombine_regions ();
7507 commit_reversible_command ();
7511 Editor::toggle_midi_input_active (bool flip_others)
7514 boost::shared_ptr<RouteList> rl (new RouteList);
7516 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7517 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7523 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7526 rl->push_back (rtav->route());
7527 onoff = !mt->input_active();
7531 _session->set_exclusive_input_active (rl, onoff, flip_others);
7538 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7540 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7541 lock_dialog->get_vbox()->pack_start (*padlock);
7543 ArdourButton* b = manage (new ArdourButton);
7544 b->set_name ("lock button");
7545 b->set_text (_("Click to unlock"));
7546 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7547 lock_dialog->get_vbox()->pack_start (*b);
7549 lock_dialog->get_vbox()->show_all ();
7550 lock_dialog->set_size_request (200, 200);
7554 /* The global menu bar continues to be accessible to applications
7555 with modal dialogs, which means that we need to desensitize
7556 all items in the menu bar. Since those items are really just
7557 proxies for actions, that means disabling all actions.
7559 ActionManager::disable_all_actions ();
7561 lock_dialog->present ();
7567 lock_dialog->hide ();
7570 ActionManager::pop_action_state ();
7573 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7574 start_lock_event_timing ();
7579 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7581 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7585 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7587 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7588 Gtkmm2ext::UI::instance()->flush_pending ();
7592 Editor::bring_all_sources_into_session ()
7599 ArdourDialog w (_("Moving embedded files into session folder"));
7600 w.get_vbox()->pack_start (msg);
7603 /* flush all pending GUI events because we're about to start copying
7607 Gtkmm2ext::UI::instance()->flush_pending ();
7611 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));