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_selection_op (_("alter selection"));
340 selection->set_preserving_all_ranges (start, end);
341 commit_reversible_selection_op ();
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 ()
2176 XMLNode &before = _session->locations()->get_state();
2177 bool removed = false;
2179 //find location(s) at this time
2180 Locations::LocationList locs;
2181 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2182 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2183 if ((*i)->is_mark()) {
2184 _session->locations()->remove (*i);
2191 begin_reversible_command (_("remove marker"));
2192 XMLNode &after = _session->locations()->get_state();
2193 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2195 commit_reversible_command ();
2200 /** Add a range marker around each selected region */
2202 Editor::add_locations_from_region ()
2204 RegionSelection rs = get_regions_from_selection_and_entered ();
2210 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2212 XMLNode &before = _session->locations()->get_state();
2214 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2216 boost::shared_ptr<Region> region = (*i)->region ();
2218 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2220 _session->locations()->add (location, true);
2223 XMLNode &after = _session->locations()->get_state();
2224 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2226 commit_reversible_command ();
2229 /** Add a single range marker around all selected regions */
2231 Editor::add_location_from_region ()
2233 RegionSelection rs = get_regions_from_selection_and_entered ();
2239 XMLNode &before = _session->locations()->get_state();
2243 if (rs.size() > 1) {
2244 _session->locations()->next_available_name(markername, "regions");
2246 RegionView* rv = *(rs.begin());
2247 boost::shared_ptr<Region> region = rv->region();
2248 markername = region->name();
2251 if (!choose_new_marker_name(markername)) {
2255 begin_reversible_command (_("add marker"));
2256 // single range spanning all selected
2257 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2258 _session->locations()->add (location, true);
2260 XMLNode &after = _session->locations()->get_state();
2261 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2263 commit_reversible_command ();
2269 Editor::jump_forward_to_mark ()
2275 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2281 _session->request_locate (pos, _session->transport_rolling());
2285 Editor::jump_backward_to_mark ()
2291 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2297 _session->request_locate (pos, _session->transport_rolling());
2303 framepos_t const pos = _session->audible_frame ();
2306 _session->locations()->next_available_name (markername, "mark");
2308 if (!choose_new_marker_name (markername)) {
2312 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2316 Editor::clear_markers ()
2319 begin_reversible_command (_("clear markers"));
2321 XMLNode &before = _session->locations()->get_state();
2322 _session->locations()->clear_markers ();
2323 XMLNode &after = _session->locations()->get_state();
2324 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2326 commit_reversible_command ();
2331 Editor::clear_ranges ()
2334 begin_reversible_command (_("clear ranges"));
2336 XMLNode &before = _session->locations()->get_state();
2338 _session->locations()->clear_ranges ();
2340 XMLNode &after = _session->locations()->get_state();
2341 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2343 commit_reversible_command ();
2348 Editor::clear_locations ()
2350 begin_reversible_command (_("clear locations"));
2352 XMLNode &before = _session->locations()->get_state();
2353 _session->locations()->clear ();
2354 XMLNode &after = _session->locations()->get_state();
2355 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2357 commit_reversible_command ();
2361 Editor::unhide_markers ()
2363 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2364 Location *l = (*i).first;
2365 if (l->is_hidden() && l->is_mark()) {
2366 l->set_hidden(false, this);
2372 Editor::unhide_ranges ()
2374 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2375 Location *l = (*i).first;
2376 if (l->is_hidden() && l->is_range_marker()) {
2377 l->set_hidden(false, this);
2382 /* INSERT/REPLACE */
2385 Editor::insert_region_list_selection (float times)
2387 RouteTimeAxisView *tv = 0;
2388 boost::shared_ptr<Playlist> playlist;
2390 if (clicked_routeview != 0) {
2391 tv = clicked_routeview;
2392 } else if (!selection->tracks.empty()) {
2393 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2396 } else if (entered_track != 0) {
2397 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2404 if ((playlist = tv->playlist()) == 0) {
2408 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2413 begin_reversible_command (_("insert region"));
2414 playlist->clear_changes ();
2415 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2416 if (Config->get_edit_mode() == Ripple)
2417 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2419 _session->add_command(new StatefulDiffCommand (playlist));
2420 commit_reversible_command ();
2423 /* BUILT-IN EFFECTS */
2426 Editor::reverse_selection ()
2431 /* GAIN ENVELOPE EDITING */
2434 Editor::edit_envelope ()
2441 Editor::transition_to_rolling (bool fwd)
2447 if (_session->config.get_external_sync()) {
2448 switch (Config->get_sync_source()) {
2452 /* transport controlled by the master */
2457 if (_session->is_auditioning()) {
2458 _session->cancel_audition ();
2462 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2466 Editor::play_from_start ()
2468 _session->request_locate (_session->current_start_frame(), true);
2472 Editor::play_from_edit_point ()
2474 _session->request_locate (get_preferred_edit_position(), true);
2478 Editor::play_from_edit_point_and_return ()
2480 framepos_t start_frame;
2481 framepos_t return_frame;
2483 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2485 if (_session->transport_rolling()) {
2486 _session->request_locate (start_frame, false);
2490 /* don't reset the return frame if its already set */
2492 if ((return_frame = _session->requested_return_frame()) < 0) {
2493 return_frame = _session->audible_frame();
2496 if (start_frame >= 0) {
2497 _session->request_roll_at_and_return (start_frame, return_frame);
2502 Editor::play_selection ()
2504 framepos_t start, end;
2505 if (!get_selection_extents ( start, end))
2508 AudioRange ar (start, end, 0);
2509 list<AudioRange> lar;
2512 _session->request_play_range (&lar, true);
2516 Editor::get_preroll ()
2518 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2523 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2525 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2528 location -= get_preroll();
2530 //don't try to locate before the beginning of time
2534 //if follow_playhead is on, keep the playhead on the screen
2535 if ( _follow_playhead )
2536 if ( location < leftmost_frame )
2537 location = leftmost_frame;
2539 _session->request_locate( location );
2543 Editor::play_with_preroll ()
2546 framepos_t preroll = get_preroll();
2548 framepos_t start, end;
2549 if (!get_selection_extents ( start, end))
2552 if (start > preroll)
2553 start = start - preroll;
2555 end = end + preroll; //"post-roll"
2557 AudioRange ar (start, end, 0);
2558 list<AudioRange> lar;
2561 _session->request_play_range (&lar, true);
2566 Editor::play_location (Location& location)
2568 if (location.start() <= location.end()) {
2572 _session->request_bounded_roll (location.start(), location.end());
2576 Editor::loop_location (Location& location)
2578 if (location.start() <= location.end()) {
2584 if ((tll = transport_loop_location()) != 0) {
2585 tll->set (location.start(), location.end());
2587 // enable looping, reposition and start rolling
2588 _session->request_locate (tll->start(), true);
2589 _session->request_play_loop (true);
2594 Editor::do_layer_operation (LayerOperation op)
2596 if (selection->regions.empty ()) {
2600 bool const multiple = selection->regions.size() > 1;
2604 begin_reversible_command (_("raise regions"));
2606 begin_reversible_command (_("raise region"));
2612 begin_reversible_command (_("raise regions to top"));
2614 begin_reversible_command (_("raise region to top"));
2620 begin_reversible_command (_("lower regions"));
2622 begin_reversible_command (_("lower region"));
2628 begin_reversible_command (_("lower regions to bottom"));
2630 begin_reversible_command (_("lower region"));
2635 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2636 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2637 (*i)->clear_owned_changes ();
2640 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2641 boost::shared_ptr<Region> r = (*i)->region ();
2653 r->lower_to_bottom ();
2657 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2658 vector<Command*> cmds;
2660 _session->add_commands (cmds);
2663 commit_reversible_command ();
2667 Editor::raise_region ()
2669 do_layer_operation (Raise);
2673 Editor::raise_region_to_top ()
2675 do_layer_operation (RaiseToTop);
2679 Editor::lower_region ()
2681 do_layer_operation (Lower);
2685 Editor::lower_region_to_bottom ()
2687 do_layer_operation (LowerToBottom);
2690 /** Show the region editor for the selected regions */
2692 Editor::show_region_properties ()
2694 selection->foreach_regionview (&RegionView::show_region_editor);
2697 /** Show the midi list editor for the selected MIDI regions */
2699 Editor::show_midi_list_editor ()
2701 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2705 Editor::rename_region ()
2707 RegionSelection rs = get_regions_from_selection_and_entered ();
2713 ArdourDialog d (*this, _("Rename Region"), true, false);
2715 Label label (_("New name:"));
2718 hbox.set_spacing (6);
2719 hbox.pack_start (label, false, false);
2720 hbox.pack_start (entry, true, true);
2722 d.get_vbox()->set_border_width (12);
2723 d.get_vbox()->pack_start (hbox, false, false);
2725 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2726 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2728 d.set_size_request (300, -1);
2730 entry.set_text (rs.front()->region()->name());
2731 entry.select_region (0, -1);
2733 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2739 int const ret = d.run();
2743 if (ret != RESPONSE_OK) {
2747 std::string str = entry.get_text();
2748 strip_whitespace_edges (str);
2750 rs.front()->region()->set_name (str);
2751 _regions->redisplay ();
2756 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2758 if (_session->is_auditioning()) {
2759 _session->cancel_audition ();
2762 // note: some potential for creativity here, because region doesn't
2763 // have to belong to the playlist that Route is handling
2765 // bool was_soloed = route.soloed();
2767 route.set_solo (true, this);
2769 _session->request_bounded_roll (region->position(), region->position() + region->length());
2771 /* XXX how to unset the solo state ? */
2774 /** Start an audition of the first selected region */
2776 Editor::play_edit_range ()
2778 framepos_t start, end;
2780 if (get_edit_op_range (start, end)) {
2781 _session->request_bounded_roll (start, end);
2786 Editor::play_selected_region ()
2788 framepos_t start = max_framepos;
2791 RegionSelection rs = get_regions_from_selection_and_entered ();
2797 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2798 if ((*i)->region()->position() < start) {
2799 start = (*i)->region()->position();
2801 if ((*i)->region()->last_frame() + 1 > end) {
2802 end = (*i)->region()->last_frame() + 1;
2806 _session->request_bounded_roll (start, end);
2810 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2812 _session->audition_region (region);
2816 Editor::region_from_selection ()
2818 if (clicked_axisview == 0) {
2822 if (selection->time.empty()) {
2826 framepos_t start = selection->time[clicked_selection].start;
2827 framepos_t end = selection->time[clicked_selection].end;
2829 TrackViewList tracks = get_tracks_for_range_action ();
2831 framepos_t selection_cnt = end - start + 1;
2833 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2834 boost::shared_ptr<Region> current;
2835 boost::shared_ptr<Playlist> pl;
2836 framepos_t internal_start;
2839 if ((pl = (*i)->playlist()) == 0) {
2843 if ((current = pl->top_region_at (start)) == 0) {
2847 internal_start = start - current->position();
2848 RegionFactory::region_name (new_name, current->name(), true);
2852 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2853 plist.add (ARDOUR::Properties::length, selection_cnt);
2854 plist.add (ARDOUR::Properties::name, new_name);
2855 plist.add (ARDOUR::Properties::layer, 0);
2857 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2862 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2864 if (selection->time.empty() || selection->tracks.empty()) {
2868 framepos_t start, end;
2869 if (clicked_selection) {
2870 start = selection->time[clicked_selection].start;
2871 end = selection->time[clicked_selection].end;
2873 start = selection->time.start();
2874 end = selection->time.end_frame();
2877 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2878 sort_track_selection (ts);
2880 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2881 boost::shared_ptr<Region> current;
2882 boost::shared_ptr<Playlist> playlist;
2883 framepos_t internal_start;
2886 if ((playlist = (*i)->playlist()) == 0) {
2890 if ((current = playlist->top_region_at(start)) == 0) {
2894 internal_start = start - current->position();
2895 RegionFactory::region_name (new_name, current->name(), true);
2899 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2900 plist.add (ARDOUR::Properties::length, end - start + 1);
2901 plist.add (ARDOUR::Properties::name, new_name);
2903 new_regions.push_back (RegionFactory::create (current, plist));
2908 Editor::split_multichannel_region ()
2910 RegionSelection rs = get_regions_from_selection_and_entered ();
2916 vector< boost::shared_ptr<Region> > v;
2918 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2919 (*x)->region()->separate_by_channel (*_session, v);
2924 Editor::new_region_from_selection ()
2926 region_from_selection ();
2927 cancel_selection ();
2931 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2933 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2934 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2935 case Evoral::OverlapNone:
2943 * - selected tracks, or if there are none...
2944 * - tracks containing selected regions, or if there are none...
2949 Editor::get_tracks_for_range_action () const
2953 if (selection->tracks.empty()) {
2955 /* use tracks with selected regions */
2957 RegionSelection rs = selection->regions;
2959 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2960 TimeAxisView* tv = &(*i)->get_time_axis_view();
2962 if (!t.contains (tv)) {
2968 /* no regions and no tracks: use all tracks */
2974 t = selection->tracks;
2977 return t.filter_to_unique_playlists();
2981 Editor::separate_regions_between (const TimeSelection& ts)
2983 bool in_command = false;
2984 boost::shared_ptr<Playlist> playlist;
2985 RegionSelection new_selection;
2987 TrackViewList tmptracks = get_tracks_for_range_action ();
2988 sort_track_selection (tmptracks);
2990 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2992 RouteTimeAxisView* rtv;
2994 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2996 if (rtv->is_track()) {
2998 /* no edits to destructive tracks */
3000 if (rtv->track()->destructive()) {
3004 if ((playlist = rtv->playlist()) != 0) {
3006 playlist->clear_changes ();
3008 /* XXX need to consider musical time selections here at some point */
3010 double speed = rtv->track()->speed();
3013 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3015 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3016 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3018 latest_regionviews.clear ();
3020 playlist->partition ((framepos_t)((*t).start * speed),
3021 (framepos_t)((*t).end * speed), false);
3025 if (!latest_regionviews.empty()) {
3027 rtv->view()->foreach_regionview (sigc::bind (
3028 sigc::ptr_fun (add_if_covered),
3029 &(*t), &new_selection));
3032 begin_reversible_command (_("separate"));
3036 /* pick up changes to existing regions */
3038 vector<Command*> cmds;
3039 playlist->rdiff (cmds);
3040 _session->add_commands (cmds);
3042 /* pick up changes to the playlist itself (adds/removes)
3045 _session->add_command(new StatefulDiffCommand (playlist));
3054 // selection->set (new_selection);
3056 commit_reversible_command ();
3060 struct PlaylistState {
3061 boost::shared_ptr<Playlist> playlist;
3065 /** Take tracks from get_tracks_for_range_action and cut any regions
3066 * on those tracks so that the tracks are empty over the time
3070 Editor::separate_region_from_selection ()
3072 /* preferentially use *all* ranges in the time selection if we're in range mode
3073 to allow discontiguous operation, since get_edit_op_range() currently
3074 returns a single range.
3077 if (!selection->time.empty()) {
3079 separate_regions_between (selection->time);
3086 if (get_edit_op_range (start, end)) {
3088 AudioRange ar (start, end, 1);
3092 separate_regions_between (ts);
3098 Editor::separate_region_from_punch ()
3100 Location* loc = _session->locations()->auto_punch_location();
3102 separate_regions_using_location (*loc);
3107 Editor::separate_region_from_loop ()
3109 Location* loc = _session->locations()->auto_loop_location();
3111 separate_regions_using_location (*loc);
3116 Editor::separate_regions_using_location (Location& loc)
3118 if (loc.is_mark()) {
3122 AudioRange ar (loc.start(), loc.end(), 1);
3127 separate_regions_between (ts);
3130 /** Separate regions under the selected region */
3132 Editor::separate_under_selected_regions ()
3134 vector<PlaylistState> playlists;
3138 rs = get_regions_from_selection_and_entered();
3140 if (!_session || rs.empty()) {
3144 begin_reversible_command (_("separate region under"));
3146 list<boost::shared_ptr<Region> > regions_to_remove;
3148 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3149 // we can't just remove the region(s) in this loop because
3150 // this removes them from the RegionSelection, and they thus
3151 // disappear from underneath the iterator, and the ++i above
3152 // SEGVs in a puzzling fashion.
3154 // so, first iterate over the regions to be removed from rs and
3155 // add them to the regions_to_remove list, and then
3156 // iterate over the list to actually remove them.
3158 regions_to_remove.push_back ((*i)->region());
3161 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3163 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3166 // is this check necessary?
3170 vector<PlaylistState>::iterator i;
3172 //only take state if this is a new playlist.
3173 for (i = playlists.begin(); i != playlists.end(); ++i) {
3174 if ((*i).playlist == playlist) {
3179 if (i == playlists.end()) {
3181 PlaylistState before;
3182 before.playlist = playlist;
3183 before.before = &playlist->get_state();
3185 playlist->freeze ();
3186 playlists.push_back(before);
3189 //Partition on the region bounds
3190 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3192 //Re-add region that was just removed due to the partition operation
3193 playlist->add_region( (*rl), (*rl)->first_frame() );
3196 vector<PlaylistState>::iterator pl;
3198 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3199 (*pl).playlist->thaw ();
3200 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3203 commit_reversible_command ();
3207 Editor::crop_region_to_selection ()
3209 if (!selection->time.empty()) {
3211 crop_region_to (selection->time.start(), selection->time.end_frame());
3218 if (get_edit_op_range (start, end)) {
3219 crop_region_to (start, end);
3226 Editor::crop_region_to (framepos_t start, framepos_t end)
3228 vector<boost::shared_ptr<Playlist> > playlists;
3229 boost::shared_ptr<Playlist> playlist;
3232 if (selection->tracks.empty()) {
3233 ts = track_views.filter_to_unique_playlists();
3235 ts = selection->tracks.filter_to_unique_playlists ();
3238 sort_track_selection (ts);
3240 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3242 RouteTimeAxisView* rtv;
3244 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3246 boost::shared_ptr<Track> t = rtv->track();
3248 if (t != 0 && ! t->destructive()) {
3250 if ((playlist = rtv->playlist()) != 0) {
3251 playlists.push_back (playlist);
3257 if (playlists.empty()) {
3261 framepos_t the_start;
3265 begin_reversible_command (_("trim to selection"));
3267 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3269 boost::shared_ptr<Region> region;
3273 if ((region = (*i)->top_region_at(the_start)) == 0) {
3277 /* now adjust lengths to that we do the right thing
3278 if the selection extends beyond the region
3281 the_start = max (the_start, (framepos_t) region->position());
3282 if (max_framepos - the_start < region->length()) {
3283 the_end = the_start + region->length() - 1;
3285 the_end = max_framepos;
3287 the_end = min (end, the_end);
3288 cnt = the_end - the_start + 1;
3290 region->clear_changes ();
3291 region->trim_to (the_start, cnt);
3292 _session->add_command (new StatefulDiffCommand (region));
3295 commit_reversible_command ();
3299 Editor::region_fill_track ()
3301 RegionSelection rs = get_regions_from_selection_and_entered ();
3302 bool commit = false;
3304 if (!_session || rs.empty()) {
3308 framepos_t const end = _session->current_end_frame ();
3310 begin_reversible_command (Operations::region_fill);
3312 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3314 boost::shared_ptr<Region> region ((*i)->region());
3316 boost::shared_ptr<Playlist> pl = region->playlist();
3318 if (end <= region->last_frame()) {
3322 double times = (double) (end - region->last_frame()) / (double) region->length();
3328 pl->clear_changes ();
3329 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3330 _session->add_command (new StatefulDiffCommand (pl));
3336 commit_reversible_command ();
3338 abort_reversible_command ();
3343 Editor::region_fill_selection ()
3345 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3349 if (selection->time.empty()) {
3353 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3358 framepos_t start = selection->time[clicked_selection].start;
3359 framepos_t end = selection->time[clicked_selection].end;
3361 boost::shared_ptr<Playlist> playlist;
3363 if (selection->tracks.empty()) {
3367 framepos_t selection_length = end - start;
3368 float times = (float)selection_length / region->length();
3369 bool commit = false;
3371 begin_reversible_command (Operations::fill_selection);
3373 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3375 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3377 if ((playlist = (*i)->playlist()) == 0) {
3381 playlist->clear_changes ();
3382 playlist->add_region (RegionFactory::create (region, true), start, times);
3383 _session->add_command (new StatefulDiffCommand (playlist));
3388 commit_reversible_command ();
3390 abort_reversible_command ();
3395 Editor::set_region_sync_position ()
3397 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3401 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3403 bool in_command = false;
3405 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3407 if (!(*r)->region()->covers (where)) {
3411 boost::shared_ptr<Region> region ((*r)->region());
3414 begin_reversible_command (_("set sync point"));
3418 region->clear_changes ();
3419 region->set_sync_position (where);
3420 _session->add_command(new StatefulDiffCommand (region));
3424 commit_reversible_command ();
3428 /** Remove the sync positions of the selection */
3430 Editor::remove_region_sync ()
3432 RegionSelection rs = get_regions_from_selection_and_entered ();
3438 begin_reversible_command (_("remove region sync"));
3440 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3442 (*i)->region()->clear_changes ();
3443 (*i)->region()->clear_sync_position ();
3444 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3447 commit_reversible_command ();
3451 Editor::naturalize_region ()
3453 RegionSelection rs = get_regions_from_selection_and_entered ();
3459 if (rs.size() > 1) {
3460 begin_reversible_command (_("move regions to original position"));
3462 begin_reversible_command (_("move region to original position"));
3465 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3466 (*i)->region()->clear_changes ();
3467 (*i)->region()->move_to_natural_position ();
3468 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3471 commit_reversible_command ();
3475 Editor::align_regions (RegionPoint what)
3477 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3483 begin_reversible_command (_("align selection"));
3485 framepos_t const position = get_preferred_edit_position ();
3487 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3488 align_region_internal ((*i)->region(), what, position);
3491 commit_reversible_command ();
3494 struct RegionSortByTime {
3495 bool operator() (const RegionView* a, const RegionView* b) {
3496 return a->region()->position() < b->region()->position();
3501 Editor::align_regions_relative (RegionPoint point)
3503 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3509 framepos_t const position = get_preferred_edit_position ();
3511 framepos_t distance = 0;
3515 list<RegionView*> sorted;
3516 rs.by_position (sorted);
3518 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3523 if (position > r->position()) {
3524 distance = position - r->position();
3526 distance = r->position() - position;
3532 if (position > r->last_frame()) {
3533 distance = position - r->last_frame();
3534 pos = r->position() + distance;
3536 distance = r->last_frame() - position;
3537 pos = r->position() - distance;
3543 pos = r->adjust_to_sync (position);
3544 if (pos > r->position()) {
3545 distance = pos - r->position();
3547 distance = r->position() - pos;
3553 if (pos == r->position()) {
3557 begin_reversible_command (_("align selection (relative)"));
3559 /* move first one specially */
3561 r->clear_changes ();
3562 r->set_position (pos);
3563 _session->add_command(new StatefulDiffCommand (r));
3565 /* move rest by the same amount */
3569 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3571 boost::shared_ptr<Region> region ((*i)->region());
3573 region->clear_changes ();
3576 region->set_position (region->position() + distance);
3578 region->set_position (region->position() - distance);
3581 _session->add_command(new StatefulDiffCommand (region));
3585 commit_reversible_command ();
3589 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3591 begin_reversible_command (_("align region"));
3592 align_region_internal (region, point, position);
3593 commit_reversible_command ();
3597 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3599 region->clear_changes ();
3603 region->set_position (region->adjust_to_sync (position));
3607 if (position > region->length()) {
3608 region->set_position (position - region->length());
3613 region->set_position (position);
3617 _session->add_command(new StatefulDiffCommand (region));
3621 Editor::trim_region_front ()
3627 Editor::trim_region_back ()
3629 trim_region (false);
3633 Editor::trim_region (bool front)
3635 framepos_t where = get_preferred_edit_position();
3636 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3642 begin_reversible_command (front ? _("trim front") : _("trim back"));
3644 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3645 if (!(*i)->region()->locked()) {
3647 (*i)->region()->clear_changes ();
3650 (*i)->region()->trim_front (where);
3651 maybe_locate_with_edit_preroll ( where );
3653 (*i)->region()->trim_end (where);
3654 maybe_locate_with_edit_preroll ( where );
3657 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3661 commit_reversible_command ();
3664 /** Trim the end of the selected regions to the position of the edit cursor */
3666 Editor::trim_region_to_loop ()
3668 Location* loc = _session->locations()->auto_loop_location();
3672 trim_region_to_location (*loc, _("trim to loop"));
3676 Editor::trim_region_to_punch ()
3678 Location* loc = _session->locations()->auto_punch_location();
3682 trim_region_to_location (*loc, _("trim to punch"));
3686 Editor::trim_region_to_location (const Location& loc, const char* str)
3688 RegionSelection rs = get_regions_from_selection_and_entered ();
3690 begin_reversible_command (str);
3692 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3693 RegionView* rv = (*x);
3695 /* require region to span proposed trim */
3696 switch (rv->region()->coverage (loc.start(), loc.end())) {
3697 case Evoral::OverlapInternal:
3703 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3712 if (tav->track() != 0) {
3713 speed = tav->track()->speed();
3716 start = session_frame_to_track_frame (loc.start(), speed);
3717 end = session_frame_to_track_frame (loc.end(), speed);
3719 rv->region()->clear_changes ();
3720 rv->region()->trim_to (start, (end - start));
3721 _session->add_command(new StatefulDiffCommand (rv->region()));
3724 commit_reversible_command ();
3728 Editor::trim_region_to_previous_region_end ()
3730 return trim_to_region(false);
3734 Editor::trim_region_to_next_region_start ()
3736 return trim_to_region(true);
3740 Editor::trim_to_region(bool forward)
3742 RegionSelection rs = get_regions_from_selection_and_entered ();
3743 bool commit = false;
3744 begin_reversible_command (_("trim to region"));
3746 boost::shared_ptr<Region> next_region;
3748 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3750 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3756 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3764 if (atav->track() != 0) {
3765 speed = atav->track()->speed();
3769 boost::shared_ptr<Region> region = arv->region();
3770 boost::shared_ptr<Playlist> playlist (region->playlist());
3772 region->clear_changes ();
3776 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3782 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3783 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3787 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3793 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3795 arv->region_changed (ARDOUR::bounds_change);
3798 _session->add_command(new StatefulDiffCommand (region));
3803 commit_reversible_command ();
3805 abort_reversible_command ();
3810 Editor::unfreeze_route ()
3812 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3816 clicked_routeview->track()->unfreeze ();
3820 Editor::_freeze_thread (void* arg)
3822 return static_cast<Editor*>(arg)->freeze_thread ();
3826 Editor::freeze_thread ()
3828 /* create event pool because we may need to talk to the session */
3829 SessionEvent::create_per_thread_pool ("freeze events", 64);
3830 /* create per-thread buffers for process() tree to use */
3831 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3832 current_interthread_info->done = true;
3837 Editor::freeze_route ()
3843 /* stop transport before we start. this is important */
3845 _session->request_transport_speed (0.0);
3847 /* wait for just a little while, because the above call is asynchronous */
3849 Glib::usleep (250000);
3851 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3855 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3857 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3858 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3860 d.set_title (_("Cannot freeze"));
3865 if (clicked_routeview->track()->has_external_redirects()) {
3866 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"
3867 "Freezing will only process the signal as far as the first send/insert/return."),
3868 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3870 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3871 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3872 d.set_title (_("Freeze Limits"));
3874 int response = d.run ();
3877 case Gtk::RESPONSE_CANCEL:
3884 InterThreadInfo itt;
3885 current_interthread_info = &itt;
3887 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3889 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3891 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3893 while (!itt.done && !itt.cancel) {
3894 gtk_main_iteration ();
3897 current_interthread_info = 0;
3901 Editor::bounce_range_selection (bool replace, bool enable_processing)
3903 if (selection->time.empty()) {
3907 TrackSelection views = selection->tracks;
3909 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3911 if (enable_processing) {
3913 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3915 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3917 _("You can't perform this operation because the processing of the signal "
3918 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3919 "You can do this without processing, which is a different operation.")
3921 d.set_title (_("Cannot bounce"));
3928 framepos_t start = selection->time[clicked_selection].start;
3929 framepos_t end = selection->time[clicked_selection].end;
3930 framepos_t cnt = end - start + 1;
3932 begin_reversible_command (_("bounce range"));
3934 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3936 RouteTimeAxisView* rtv;
3938 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3942 boost::shared_ptr<Playlist> playlist;
3944 if ((playlist = rtv->playlist()) == 0) {
3948 InterThreadInfo itt;
3950 playlist->clear_changes ();
3951 playlist->clear_owned_changes ();
3953 boost::shared_ptr<Region> r;
3955 if (enable_processing) {
3956 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3958 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3966 list<AudioRange> ranges;
3967 ranges.push_back (AudioRange (start, start+cnt, 0));
3968 playlist->cut (ranges); // discard result
3969 playlist->add_region (r, start);
3972 vector<Command*> cmds;
3973 playlist->rdiff (cmds);
3974 _session->add_commands (cmds);
3976 _session->add_command (new StatefulDiffCommand (playlist));
3979 commit_reversible_command ();
3982 /** Delete selected regions, automation points or a time range */
3986 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3987 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3988 bool deleted = false;
3989 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3990 deleted = current_mixer_strip->delete_processors ();
3996 /** Cut selected regions, automation points or a time range */
4003 /** Copy selected regions, automation points or a time range */
4011 /** @return true if a Cut, Copy or Clear is possible */
4013 Editor::can_cut_copy () const
4015 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4022 /** Cut, copy or clear selected regions, automation points or a time range.
4023 * @param op Operation (Delete, Cut, Copy or Clear)
4026 Editor::cut_copy (CutCopyOp op)
4028 /* only cancel selection if cut/copy is successful.*/
4034 opname = _("delete");
4043 opname = _("clear");
4047 /* if we're deleting something, and the mouse is still pressed,
4048 the thing we started a drag for will be gone when we release
4049 the mouse button(s). avoid this. see part 2 at the end of
4053 if (op == Delete || op == Cut || op == Clear) {
4054 if (_drags->active ()) {
4059 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4060 cut_buffer->clear ();
4062 if (entered_marker) {
4064 /* cut/delete op while pointing at a marker */
4067 Location* loc = find_location_from_marker (entered_marker, ignored);
4069 if (_session && loc) {
4070 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4077 switch (mouse_mode) {
4080 begin_reversible_command (opname + ' ' + X_("MIDI"));
4082 commit_reversible_command ();
4088 bool did_edit = false;
4090 if (!selection->regions.empty() || !selection->points.empty()) {
4091 begin_reversible_command (opname + ' ' + _("objects"));
4094 if (!selection->regions.empty()) {
4095 cut_copy_regions (op, selection->regions);
4097 if (op == Cut || op == Delete) {
4098 selection->clear_regions ();
4102 if (!selection->points.empty()) {
4103 cut_copy_points (op);
4105 if (op == Cut || op == Delete) {
4106 selection->clear_points ();
4109 } else if (selection->time.empty()) {
4110 framepos_t start, end;
4111 /* no time selection, see if we can get an edit range
4114 if (get_edit_op_range (start, end)) {
4115 selection->set (start, end);
4117 } else if (!selection->time.empty()) {
4118 begin_reversible_command (opname + ' ' + _("range"));
4121 cut_copy_ranges (op);
4123 if (op == Cut || op == Delete) {
4124 selection->clear_time ();
4129 /* reset repeated paste state */
4132 commit_reversible_command ();
4135 if (op == Delete || op == Cut || op == Clear) {
4140 struct AutomationRecord {
4141 AutomationRecord () : state (0) , line(NULL) {}
4142 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4144 XMLNode* state; ///< state before any operation
4145 const AutomationLine* line; ///< line this came from
4146 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4149 /** Cut, copy or clear selected automation points.
4150 * @param op Operation (Cut, Copy or Clear)
4153 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4155 if (selection->points.empty ()) {
4159 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4160 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4162 /* Keep a record of the AutomationLists that we end up using in this operation */
4163 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4166 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4167 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4168 const AutomationLine& line = (*i)->line();
4169 const boost::shared_ptr<AutomationList> al = line.the_list();
4170 if (lists.find (al) == lists.end ()) {
4171 /* We haven't seen this list yet, so make a record for it. This includes
4172 taking a copy of its current state, in case this is needed for undo later.
4174 lists[al] = AutomationRecord (&al->get_state (), &line);
4178 if (op == Cut || op == Copy) {
4179 /* This operation will involve putting things in the cut buffer, so create an empty
4180 ControlList for each of our source lists to put the cut buffer data in.
4182 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4183 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4186 /* Add all selected points to the relevant copy ControlLists */
4187 framepos_t start = std::numeric_limits<framepos_t>::max();
4188 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4189 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4190 AutomationList::const_iterator j = (*i)->model();
4192 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4194 /* Update earliest MIDI start time in beats */
4195 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4197 /* Update earliest session start time in frames */
4198 start = std::min(start, (*i)->line().session_position(j));
4202 /* Snap start time backwards, so copy/paste is snap aligned. */
4204 if (earliest == Evoral::Beats::max()) {
4205 earliest = Evoral::Beats(); // Weird... don't offset
4207 earliest.round_down_to_beat();
4209 if (start == std::numeric_limits<double>::max()) {
4210 start = 0; // Weird... don't offset
4212 snap_to(start, RoundDownMaybe);
4215 const double line_offset = midi ? earliest.to_double() : start;
4216 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4217 /* Correct this copy list so that it is relative to the earliest
4218 start time, so relative ordering between points is preserved
4219 when copying from several lists and the paste starts at the
4220 earliest copied piece of data. */
4221 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4222 (*j)->when -= line_offset;
4225 /* And add it to the cut buffer */
4226 cut_buffer->add (i->second.copy);
4230 if (op == Delete || op == Cut) {
4231 /* This operation needs to remove things from the main AutomationList, so do that now */
4233 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4234 i->first->freeze ();
4237 /* Remove each selected point from its AutomationList */
4238 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4239 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4240 al->erase ((*i)->model ());
4243 /* Thaw the lists and add undo records for them */
4244 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4245 boost::shared_ptr<AutomationList> al = i->first;
4247 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4252 /** Cut, copy or clear selected automation points.
4253 * @param op Operation (Cut, Copy or Clear)
4256 Editor::cut_copy_midi (CutCopyOp op)
4258 Evoral::Beats earliest = Evoral::Beats::max();
4259 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4260 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4262 if (!mrv->selection().empty()) {
4263 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4265 mrv->cut_copy_clear (op);
4267 /* XXX: not ideal, as there may be more than one track involved in the selection */
4268 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4272 if (!selection->points.empty()) {
4273 cut_copy_points (op, earliest, true);
4274 if (op == Cut || op == Delete) {
4275 selection->clear_points ();
4280 struct lt_playlist {
4281 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4282 return a.playlist < b.playlist;
4286 struct PlaylistMapping {
4288 boost::shared_ptr<Playlist> pl;
4290 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4293 /** Remove `clicked_regionview' */
4295 Editor::remove_clicked_region ()
4297 if (clicked_routeview == 0 || clicked_regionview == 0) {
4301 begin_reversible_command (_("remove region"));
4303 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4305 playlist->clear_changes ();
4306 playlist->clear_owned_changes ();
4307 playlist->remove_region (clicked_regionview->region());
4308 if (Config->get_edit_mode() == Ripple)
4309 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4311 /* We might have removed regions, which alters other regions' layering_index,
4312 so we need to do a recursive diff here.
4314 vector<Command*> cmds;
4315 playlist->rdiff (cmds);
4316 _session->add_commands (cmds);
4318 _session->add_command(new StatefulDiffCommand (playlist));
4319 commit_reversible_command ();
4323 /** Remove the selected regions */
4325 Editor::remove_selected_regions ()
4327 RegionSelection rs = get_regions_from_selection_and_entered ();
4329 if (!_session || rs.empty()) {
4333 begin_reversible_command (_("remove region"));
4335 list<boost::shared_ptr<Region> > regions_to_remove;
4337 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4338 // we can't just remove the region(s) in this loop because
4339 // this removes them from the RegionSelection, and they thus
4340 // disappear from underneath the iterator, and the ++i above
4341 // SEGVs in a puzzling fashion.
4343 // so, first iterate over the regions to be removed from rs and
4344 // add them to the regions_to_remove list, and then
4345 // iterate over the list to actually remove them.
4347 regions_to_remove.push_back ((*i)->region());
4350 vector<boost::shared_ptr<Playlist> > playlists;
4352 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4354 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4357 // is this check necessary?
4361 /* get_regions_from_selection_and_entered() guarantees that
4362 the playlists involved are unique, so there is no need
4366 playlists.push_back (playlist);
4368 playlist->clear_changes ();
4369 playlist->clear_owned_changes ();
4370 playlist->freeze ();
4371 playlist->remove_region (*rl);
4372 if (Config->get_edit_mode() == Ripple)
4373 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4377 vector<boost::shared_ptr<Playlist> >::iterator pl;
4379 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4382 /* We might have removed regions, which alters other regions' layering_index,
4383 so we need to do a recursive diff here.
4385 vector<Command*> cmds;
4386 (*pl)->rdiff (cmds);
4387 _session->add_commands (cmds);
4389 _session->add_command(new StatefulDiffCommand (*pl));
4392 commit_reversible_command ();
4395 /** Cut, copy or clear selected regions.
4396 * @param op Operation (Cut, Copy or Clear)
4399 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4401 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4402 a map when we want ordered access to both elements. i think.
4405 vector<PlaylistMapping> pmap;
4407 framepos_t first_position = max_framepos;
4409 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4410 FreezeList freezelist;
4412 /* get ordering correct before we cut/copy */
4414 rs.sort_by_position_and_track ();
4416 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4418 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4420 if (op == Cut || op == Clear || op == Delete) {
4421 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4424 FreezeList::iterator fl;
4426 // only take state if this is a new playlist.
4427 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4433 if (fl == freezelist.end()) {
4434 pl->clear_changes();
4435 pl->clear_owned_changes ();
4437 freezelist.insert (pl);
4442 TimeAxisView* tv = &(*x)->get_time_axis_view();
4443 vector<PlaylistMapping>::iterator z;
4445 for (z = pmap.begin(); z != pmap.end(); ++z) {
4446 if ((*z).tv == tv) {
4451 if (z == pmap.end()) {
4452 pmap.push_back (PlaylistMapping (tv));
4456 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4458 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4461 /* region not yet associated with a playlist (e.g. unfinished
4468 TimeAxisView& tv = (*x)->get_time_axis_view();
4469 boost::shared_ptr<Playlist> npl;
4470 RegionSelection::iterator tmp;
4477 vector<PlaylistMapping>::iterator z;
4479 for (z = pmap.begin(); z != pmap.end(); ++z) {
4480 if ((*z).tv == &tv) {
4485 assert (z != pmap.end());
4488 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4496 boost::shared_ptr<Region> r = (*x)->region();
4497 boost::shared_ptr<Region> _xx;
4503 pl->remove_region (r);
4504 if (Config->get_edit_mode() == Ripple)
4505 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4509 _xx = RegionFactory::create (r);
4510 npl->add_region (_xx, r->position() - first_position);
4511 pl->remove_region (r);
4512 if (Config->get_edit_mode() == Ripple)
4513 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4517 /* copy region before adding, so we're not putting same object into two different playlists */
4518 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4522 pl->remove_region (r);
4523 if (Config->get_edit_mode() == Ripple)
4524 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4533 list<boost::shared_ptr<Playlist> > foo;
4535 /* the pmap is in the same order as the tracks in which selected regions occured */
4537 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4540 foo.push_back ((*i).pl);
4545 cut_buffer->set (foo);
4549 _last_cut_copy_source_track = 0;
4551 _last_cut_copy_source_track = pmap.front().tv;
4555 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4558 /* We might have removed regions, which alters other regions' layering_index,
4559 so we need to do a recursive diff here.
4561 vector<Command*> cmds;
4562 (*pl)->rdiff (cmds);
4563 _session->add_commands (cmds);
4565 _session->add_command (new StatefulDiffCommand (*pl));
4570 Editor::cut_copy_ranges (CutCopyOp op)
4572 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4574 /* Sort the track selection now, so that it if is used, the playlists
4575 selected by the calls below to cut_copy_clear are in the order that
4576 their tracks appear in the editor. This makes things like paste
4577 of ranges work properly.
4580 sort_track_selection (ts);
4583 if (!entered_track) {
4586 ts.push_back (entered_track);
4589 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4590 (*i)->cut_copy_clear (*selection, op);
4595 Editor::paste (float times, bool from_context)
4597 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4599 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4603 Editor::mouse_paste ()
4608 if (!mouse_frame (where, ignored)) {
4613 paste_internal (where, 1);
4617 Editor::paste_internal (framepos_t position, float times)
4619 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4621 if (cut_buffer->empty(internal_editing())) {
4625 if (position == max_framepos) {
4626 position = get_preferred_edit_position();
4627 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4630 if (position == last_paste_pos) {
4631 /* repeated paste in the same position */
4634 /* paste in new location, reset repeated paste state */
4636 last_paste_pos = position;
4639 /* get everything in the correct order */
4642 if (!selection->tracks.empty()) {
4643 /* If there is a track selection, paste into exactly those tracks and
4644 only those tracks. This allows the user to be explicit and override
4645 the below "do the reasonable thing" logic. */
4646 ts = selection->tracks.filter_to_unique_playlists ();
4647 sort_track_selection (ts);
4649 /* Figure out which track to base the paste at. */
4650 TimeAxisView* base_track = NULL;
4651 if (_edit_point == Editing::EditAtMouse && entered_track) {
4652 /* With the mouse edit point, paste onto the track under the mouse. */
4653 base_track = entered_track;
4654 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4655 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4656 base_track = &entered_regionview->get_time_axis_view();
4657 } else if (_last_cut_copy_source_track) {
4658 /* Paste to the track that the cut/copy came from (see mantis #333). */
4659 base_track = _last_cut_copy_source_track;
4661 /* This is "impossible" since we've copied... well, do nothing. */
4665 /* Walk up to parent if necessary, so base track is a route. */
4666 while (base_track->get_parent()) {
4667 base_track = base_track->get_parent();
4670 /* Add base track and all tracks below it. The paste logic will select
4671 the appropriate object types from the cut buffer in relative order. */
4672 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4673 if ((*i)->order() >= base_track->order()) {
4678 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4679 sort_track_selection (ts);
4681 /* Add automation children of each track in order, for pasting several lines. */
4682 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4683 /* Add any automation children for pasting several lines */
4684 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4689 typedef RouteTimeAxisView::AutomationTracks ATracks;
4690 const ATracks& atracks = rtv->automation_tracks();
4691 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4692 i = ts.insert(i, a->second.get());
4697 /* We now have a list of trackviews starting at base_track, including
4698 automation children, in the order shown in the editor, e.g. R1,
4699 R1.A1, R1.A2, R2, R2.A1, ... */
4702 begin_reversible_command (Operations::paste);
4704 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4705 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4706 /* Only one line copied, and one automation track selected. Do a
4707 "greedy" paste from one automation type to another. */
4709 PasteContext ctx(paste_count, times, ItemCounts(), true);
4710 ts.front()->paste (position, *cut_buffer, ctx);
4714 /* Paste into tracks */
4716 PasteContext ctx(paste_count, times, ItemCounts(), false);
4717 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4718 (*i)->paste (position, *cut_buffer, ctx);
4722 commit_reversible_command ();
4726 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4728 boost::shared_ptr<Playlist> playlist;
4729 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4730 RegionSelection foo;
4732 framepos_t const start_frame = regions.start ();
4733 framepos_t const end_frame = regions.end_frame ();
4735 begin_reversible_command (Operations::duplicate_region);
4737 selection->clear_regions ();
4739 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4741 boost::shared_ptr<Region> r ((*i)->region());
4743 TimeAxisView& tv = (*i)->get_time_axis_view();
4744 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4745 latest_regionviews.clear ();
4746 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4748 playlist = (*i)->region()->playlist();
4749 playlist->clear_changes ();
4750 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4751 _session->add_command(new StatefulDiffCommand (playlist));
4755 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4759 selection->set (foo);
4762 commit_reversible_command ();
4766 Editor::duplicate_selection (float times)
4768 if (selection->time.empty() || selection->tracks.empty()) {
4772 boost::shared_ptr<Playlist> playlist;
4773 vector<boost::shared_ptr<Region> > new_regions;
4774 vector<boost::shared_ptr<Region> >::iterator ri;
4776 create_region_from_selection (new_regions);
4778 if (new_regions.empty()) {
4782 begin_reversible_command (_("duplicate selection"));
4784 ri = new_regions.begin();
4786 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4788 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4789 if ((playlist = (*i)->playlist()) == 0) {
4792 playlist->clear_changes ();
4794 if (clicked_selection) {
4795 end = selection->time[clicked_selection].end;
4797 end = selection->time.end_frame();
4799 playlist->duplicate (*ri, end, times);
4800 _session->add_command (new StatefulDiffCommand (playlist));
4803 if (ri == new_regions.end()) {
4808 commit_reversible_command ();
4811 /** Reset all selected points to the relevant default value */
4813 Editor::reset_point_selection ()
4815 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4816 ARDOUR::AutomationList::iterator j = (*i)->model ();
4817 (*j)->value = (*i)->line().the_list()->default_value ();
4822 Editor::center_playhead ()
4824 float const page = _visible_canvas_width * samples_per_pixel;
4825 center_screen_internal (playhead_cursor->current_frame (), page);
4829 Editor::center_edit_point ()
4831 float const page = _visible_canvas_width * samples_per_pixel;
4832 center_screen_internal (get_preferred_edit_position(), page);
4835 /** Caller must begin and commit a reversible command */
4837 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4839 playlist->clear_changes ();
4841 _session->add_command (new StatefulDiffCommand (playlist));
4845 Editor::nudge_track (bool use_edit, bool forwards)
4847 boost::shared_ptr<Playlist> playlist;
4848 framepos_t distance;
4849 framepos_t next_distance;
4853 start = get_preferred_edit_position();
4858 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4862 if (selection->tracks.empty()) {
4866 begin_reversible_command (_("nudge track"));
4868 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4870 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4872 if ((playlist = (*i)->playlist()) == 0) {
4876 playlist->clear_changes ();
4877 playlist->clear_owned_changes ();
4879 playlist->nudge_after (start, distance, forwards);
4881 vector<Command*> cmds;
4883 playlist->rdiff (cmds);
4884 _session->add_commands (cmds);
4886 _session->add_command (new StatefulDiffCommand (playlist));
4889 commit_reversible_command ();
4893 Editor::remove_last_capture ()
4895 vector<string> choices;
4902 if (Config->get_verify_remove_last_capture()) {
4903 prompt = _("Do you really want to destroy the last capture?"
4904 "\n(This is destructive and cannot be undone)");
4906 choices.push_back (_("No, do nothing."));
4907 choices.push_back (_("Yes, destroy it."));
4909 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4911 if (prompter.run () == 1) {
4912 _session->remove_last_capture ();
4913 _regions->redisplay ();
4917 _session->remove_last_capture();
4918 _regions->redisplay ();
4923 Editor::normalize_region ()
4929 RegionSelection rs = get_regions_from_selection_and_entered ();
4935 NormalizeDialog dialog (rs.size() > 1);
4937 if (dialog.run () == RESPONSE_CANCEL) {
4941 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4944 /* XXX: should really only count audio regions here */
4945 int const regions = rs.size ();
4947 /* Make a list of the selected audio regions' maximum amplitudes, and also
4948 obtain the maximum amplitude of them all.
4950 list<double> max_amps;
4952 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4953 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4955 dialog.descend (1.0 / regions);
4956 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4959 /* the user cancelled the operation */
4963 max_amps.push_back (a);
4964 max_amp = max (max_amp, a);
4969 begin_reversible_command (_("normalize"));
4971 list<double>::const_iterator a = max_amps.begin ();
4973 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4974 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4979 arv->region()->clear_changes ();
4981 double const amp = dialog.normalize_individually() ? *a : max_amp;
4983 arv->audio_region()->normalize (amp, dialog.target ());
4984 _session->add_command (new StatefulDiffCommand (arv->region()));
4989 commit_reversible_command ();
4994 Editor::reset_region_scale_amplitude ()
5000 RegionSelection rs = get_regions_from_selection_and_entered ();
5006 begin_reversible_command ("reset gain");
5008 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5009 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5012 arv->region()->clear_changes ();
5013 arv->audio_region()->set_scale_amplitude (1.0f);
5014 _session->add_command (new StatefulDiffCommand (arv->region()));
5017 commit_reversible_command ();
5021 Editor::adjust_region_gain (bool up)
5023 RegionSelection rs = get_regions_from_selection_and_entered ();
5025 if (!_session || rs.empty()) {
5029 begin_reversible_command ("adjust region gain");
5031 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5032 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5037 arv->region()->clear_changes ();
5039 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5047 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5048 _session->add_command (new StatefulDiffCommand (arv->region()));
5051 commit_reversible_command ();
5056 Editor::reverse_region ()
5062 Reverse rev (*_session);
5063 apply_filter (rev, _("reverse regions"));
5067 Editor::strip_region_silence ()
5073 RegionSelection rs = get_regions_from_selection_and_entered ();
5079 std::list<RegionView*> audio_only;
5081 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5082 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5084 audio_only.push_back (arv);
5088 StripSilenceDialog d (_session, audio_only);
5089 int const r = d.run ();
5093 if (r == Gtk::RESPONSE_OK) {
5094 ARDOUR::AudioIntervalMap silences;
5095 d.silences (silences);
5096 StripSilence s (*_session, silences, d.fade_length());
5097 apply_filter (s, _("strip silence"), &d);
5102 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5104 Evoral::Sequence<Evoral::Beats>::Notes selected;
5105 mrv.selection_as_notelist (selected, true);
5107 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5108 v.push_back (selected);
5110 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5111 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5113 return op (mrv.midi_region()->model(), pos_beats, v);
5117 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5123 begin_reversible_command (op.name ());
5125 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5126 RegionSelection::const_iterator tmp = r;
5129 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5132 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5135 _session->add_command (cmd);
5142 commit_reversible_command ();
5146 Editor::fork_region ()
5148 RegionSelection rs = get_regions_from_selection_and_entered ();
5154 begin_reversible_command (_("Fork Region(s)"));
5156 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5159 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5160 RegionSelection::iterator tmp = r;
5163 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5167 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5168 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5169 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5171 playlist->clear_changes ();
5172 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5173 _session->add_command(new StatefulDiffCommand (playlist));
5175 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5182 commit_reversible_command ();
5186 Editor::quantize_region ()
5189 quantize_regions(get_regions_from_selection_and_entered ());
5194 Editor::quantize_regions (const RegionSelection& rs)
5196 if (rs.n_midi_regions() == 0) {
5200 QuantizeDialog* qd = new QuantizeDialog (*this);
5203 const int r = qd->run ();
5206 if (r == Gtk::RESPONSE_OK) {
5207 Quantize quant (qd->snap_start(), qd->snap_end(),
5208 qd->start_grid_size(), qd->end_grid_size(),
5209 qd->strength(), qd->swing(), qd->threshold());
5211 apply_midi_note_edit_op (quant, rs);
5216 Editor::legatize_region (bool shrink_only)
5219 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5224 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5226 if (rs.n_midi_regions() == 0) {
5230 Legatize legatize(shrink_only);
5231 apply_midi_note_edit_op (legatize, rs);
5235 Editor::transform_region ()
5238 transform_regions(get_regions_from_selection_and_entered ());
5243 Editor::transform_regions (const RegionSelection& rs)
5245 if (rs.n_midi_regions() == 0) {
5249 TransformDialog* td = new TransformDialog();
5252 const int r = td->run();
5255 if (r == Gtk::RESPONSE_OK) {
5256 Transform transform(td->get());
5257 apply_midi_note_edit_op(transform, rs);
5262 Editor::insert_patch_change (bool from_context)
5264 RegionSelection rs = get_regions_from_selection_and_entered ();
5270 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5272 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5273 there may be more than one, but the PatchChangeDialog can only offer
5274 one set of patch menus.
5276 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5278 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5279 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5281 if (d.run() == RESPONSE_CANCEL) {
5285 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5286 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5288 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5289 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5296 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5298 RegionSelection rs = get_regions_from_selection_and_entered ();
5299 bool commit = false;
5305 begin_reversible_command (command);
5307 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5311 int const N = rs.size ();
5313 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5314 RegionSelection::iterator tmp = r;
5317 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5319 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5322 progress->descend (1.0 / N);
5325 if (arv->audio_region()->apply (filter, progress) == 0) {
5327 playlist->clear_changes ();
5328 playlist->clear_owned_changes ();
5330 if (filter.results.empty ()) {
5332 /* no regions returned; remove the old one */
5333 playlist->remove_region (arv->region ());
5337 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5339 /* first region replaces the old one */
5340 playlist->replace_region (arv->region(), *res, (*res)->position());
5344 while (res != filter.results.end()) {
5345 playlist->add_region (*res, (*res)->position());
5350 /* We might have removed regions, which alters other regions' layering_index,
5351 so we need to do a recursive diff here.
5353 vector<Command*> cmds;
5354 playlist->rdiff (cmds);
5355 _session->add_commands (cmds);
5357 _session->add_command(new StatefulDiffCommand (playlist));
5364 progress->ascend ();
5373 commit_reversible_command ();
5375 abort_reversible_command ();
5380 Editor::external_edit_region ()
5386 Editor::reset_region_gain_envelopes ()
5388 RegionSelection rs = get_regions_from_selection_and_entered ();
5390 if (!_session || rs.empty()) {
5394 begin_reversible_command (_("reset region gain"));
5396 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5397 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5399 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5400 XMLNode& before (alist->get_state());
5402 arv->audio_region()->set_default_envelope ();
5403 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5407 commit_reversible_command ();
5411 Editor::set_region_gain_visibility (RegionView* rv)
5413 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5415 arv->update_envelope_visibility();
5420 Editor::set_gain_envelope_visibility ()
5426 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5427 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5429 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5435 Editor::toggle_gain_envelope_active ()
5437 if (_ignore_region_action) {
5441 RegionSelection rs = get_regions_from_selection_and_entered ();
5443 if (!_session || rs.empty()) {
5447 begin_reversible_command (_("region gain envelope active"));
5449 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5450 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5452 arv->region()->clear_changes ();
5453 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5454 _session->add_command (new StatefulDiffCommand (arv->region()));
5458 commit_reversible_command ();
5462 Editor::toggle_region_lock ()
5464 if (_ignore_region_action) {
5468 RegionSelection rs = get_regions_from_selection_and_entered ();
5470 if (!_session || rs.empty()) {
5474 begin_reversible_command (_("toggle region lock"));
5476 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5477 (*i)->region()->clear_changes ();
5478 (*i)->region()->set_locked (!(*i)->region()->locked());
5479 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5482 commit_reversible_command ();
5486 Editor::toggle_region_video_lock ()
5488 if (_ignore_region_action) {
5492 RegionSelection rs = get_regions_from_selection_and_entered ();
5494 if (!_session || rs.empty()) {
5498 begin_reversible_command (_("Toggle Video Lock"));
5500 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5501 (*i)->region()->clear_changes ();
5502 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5503 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5506 commit_reversible_command ();
5510 Editor::toggle_region_lock_style ()
5512 if (_ignore_region_action) {
5516 RegionSelection rs = get_regions_from_selection_and_entered ();
5518 if (!_session || rs.empty()) {
5522 begin_reversible_command (_("region lock style"));
5524 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5525 (*i)->region()->clear_changes ();
5526 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5527 (*i)->region()->set_position_lock_style (ns);
5528 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5531 commit_reversible_command ();
5535 Editor::toggle_opaque_region ()
5537 if (_ignore_region_action) {
5541 RegionSelection rs = get_regions_from_selection_and_entered ();
5543 if (!_session || rs.empty()) {
5547 begin_reversible_command (_("change region opacity"));
5549 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5550 (*i)->region()->clear_changes ();
5551 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5552 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5555 commit_reversible_command ();
5559 Editor::toggle_record_enable ()
5561 bool new_state = false;
5563 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5564 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5567 if (!rtav->is_track())
5571 new_state = !rtav->track()->record_enabled();
5575 rtav->track()->set_record_enabled (new_state, this);
5580 Editor::toggle_solo ()
5582 bool new_state = false;
5584 boost::shared_ptr<RouteList> rl (new RouteList);
5586 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5587 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5594 new_state = !rtav->route()->soloed ();
5598 rl->push_back (rtav->route());
5601 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5605 Editor::toggle_mute ()
5607 bool new_state = false;
5609 boost::shared_ptr<RouteList> rl (new RouteList);
5611 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5612 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5619 new_state = !rtav->route()->muted();
5623 rl->push_back (rtav->route());
5626 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5630 Editor::toggle_solo_isolate ()
5636 Editor::fade_range ()
5638 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5640 begin_reversible_command (_("fade range"));
5642 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5643 (*i)->fade_range (selection->time);
5646 commit_reversible_command ();
5651 Editor::set_fade_length (bool in)
5653 RegionSelection rs = get_regions_from_selection_and_entered ();
5659 /* we need a region to measure the offset from the start */
5661 RegionView* rv = rs.front ();
5663 framepos_t pos = get_preferred_edit_position();
5666 bool commit = false;
5668 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5669 /* edit point is outside the relevant region */
5674 if (pos <= rv->region()->position()) {
5678 len = pos - rv->region()->position();
5679 cmd = _("set fade in length");
5681 if (pos >= rv->region()->last_frame()) {
5685 len = rv->region()->last_frame() - pos;
5686 cmd = _("set fade out length");
5689 begin_reversible_command (cmd);
5691 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5692 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5698 boost::shared_ptr<AutomationList> alist;
5700 alist = tmp->audio_region()->fade_in();
5702 alist = tmp->audio_region()->fade_out();
5705 XMLNode &before = alist->get_state();
5708 tmp->audio_region()->set_fade_in_length (len);
5709 tmp->audio_region()->set_fade_in_active (true);
5711 tmp->audio_region()->set_fade_out_length (len);
5712 tmp->audio_region()->set_fade_out_active (true);
5714 XMLNode &after = alist->get_state();
5715 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5720 commit_reversible_command ();
5722 abort_reversible_command ();
5727 Editor::set_fade_in_shape (FadeShape shape)
5729 RegionSelection rs = get_regions_from_selection_and_entered ();
5734 bool commit = false;
5735 begin_reversible_command (_("set fade in shape"));
5737 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5738 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5744 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5745 XMLNode &before = alist->get_state();
5747 tmp->audio_region()->set_fade_in_shape (shape);
5749 XMLNode &after = alist->get_state();
5750 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5755 commit_reversible_command ();
5757 abort_reversible_command ();
5762 Editor::set_fade_out_shape (FadeShape shape)
5764 RegionSelection rs = get_regions_from_selection_and_entered ();
5769 bool commit = false;
5770 begin_reversible_command (_("set fade out shape"));
5772 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5773 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5779 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5780 XMLNode &before = alist->get_state();
5782 tmp->audio_region()->set_fade_out_shape (shape);
5784 XMLNode &after = alist->get_state();
5785 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5790 commit_reversible_command ();
5792 abort_reversible_command ();
5797 Editor::set_fade_in_active (bool yn)
5799 RegionSelection rs = get_regions_from_selection_and_entered ();
5804 bool commit = false;
5805 begin_reversible_command (_("set fade in active"));
5807 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5808 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5815 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5817 ar->clear_changes ();
5818 ar->set_fade_in_active (yn);
5819 _session->add_command (new StatefulDiffCommand (ar));
5824 commit_reversible_command ();
5826 abort_reversible_command ();
5831 Editor::set_fade_out_active (bool yn)
5833 RegionSelection rs = get_regions_from_selection_and_entered ();
5838 bool commit = false;
5839 begin_reversible_command (_("set fade out active"));
5841 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5842 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5848 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5850 ar->clear_changes ();
5851 ar->set_fade_out_active (yn);
5852 _session->add_command(new StatefulDiffCommand (ar));
5857 commit_reversible_command ();
5859 abort_reversible_command ();
5864 Editor::toggle_region_fades (int dir)
5866 if (_ignore_region_action) {
5870 boost::shared_ptr<AudioRegion> ar;
5873 RegionSelection rs = get_regions_from_selection_and_entered ();
5879 RegionSelection::iterator i;
5880 for (i = rs.begin(); i != rs.end(); ++i) {
5881 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5883 yn = ar->fade_out_active ();
5885 yn = ar->fade_in_active ();
5891 if (i == rs.end()) {
5895 /* XXX should this undo-able? */
5896 bool commit = false;
5897 begin_reversible_command (_("toggle fade active"));
5899 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5900 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5903 ar->clear_changes ();
5905 if (dir == 1 || dir == 0) {
5906 ar->set_fade_in_active (!yn);
5909 if (dir == -1 || dir == 0) {
5910 ar->set_fade_out_active (!yn);
5912 _session->add_command(new StatefulDiffCommand (ar));
5917 commit_reversible_command ();
5919 abort_reversible_command ();
5924 /** Update region fade visibility after its configuration has been changed */
5926 Editor::update_region_fade_visibility ()
5928 bool _fade_visibility = _session->config.get_show_region_fades ();
5930 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5931 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5933 if (_fade_visibility) {
5934 v->audio_view()->show_all_fades ();
5936 v->audio_view()->hide_all_fades ();
5943 Editor::set_edit_point ()
5948 if (!mouse_frame (where, ignored)) {
5954 if (selection->markers.empty()) {
5956 mouse_add_new_marker (where);
5961 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5964 loc->move_to (where);
5970 Editor::set_playhead_cursor ()
5972 if (entered_marker) {
5973 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5978 if (!mouse_frame (where, ignored)) {
5985 _session->request_locate (where, _session->transport_rolling());
5989 if (ARDOUR_UI::config()->get_follow_edits()) {
5990 cancel_time_selection();
5995 Editor::split_region ()
5997 //if a range is selected, separate it
5998 if ( !selection->time.empty()) {
5999 separate_regions_between (selection->time);
6003 //if no range was selected, try to find some regions to split
6004 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6006 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6008 framepos_t where = get_preferred_edit_position ();
6014 split_regions_at (where, rs);
6018 struct EditorOrderRouteSorter {
6019 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6020 return a->order_key () < b->order_key ();
6025 Editor::select_next_route()
6027 if (selection->tracks.empty()) {
6028 selection->set (track_views.front());
6032 TimeAxisView* current = selection->tracks.front();
6036 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6037 if (*i == current) {
6039 if (i != track_views.end()) {
6042 current = (*(track_views.begin()));
6043 //selection->set (*(track_views.begin()));
6048 rui = dynamic_cast<RouteUI *>(current);
6049 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6051 selection->set(current);
6053 ensure_time_axis_view_is_visible (*current, false);
6057 Editor::select_prev_route()
6059 if (selection->tracks.empty()) {
6060 selection->set (track_views.front());
6064 TimeAxisView* current = selection->tracks.front();
6068 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6069 if (*i == current) {
6071 if (i != track_views.rend()) {
6074 current = *(track_views.rbegin());
6079 rui = dynamic_cast<RouteUI *>(current);
6080 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6082 selection->set (current);
6084 ensure_time_axis_view_is_visible (*current, false);
6088 Editor::set_loop_from_selection (bool play)
6090 if (_session == 0) {
6094 framepos_t start, end;
6095 if (!get_selection_extents ( start, end))
6098 set_loop_range (start, end, _("set loop range from selection"));
6101 _session->request_play_loop (true, true);
6106 Editor::set_loop_from_region (bool play)
6108 framepos_t start, end;
6109 if (!get_selection_extents ( start, end))
6112 set_loop_range (start, end, _("set loop range from region"));
6115 _session->request_locate (start, true);
6116 _session->request_play_loop (true);
6121 Editor::set_punch_from_selection ()
6123 if (_session == 0) {
6127 framepos_t start, end;
6128 if (!get_selection_extents ( start, end))
6131 set_punch_range (start, end, _("set punch range from selection"));
6135 Editor::set_session_extents_from_selection ()
6137 if (_session == 0) {
6141 framepos_t start, end;
6142 if (!get_selection_extents ( start, end))
6146 if ((loc = _session->locations()->session_range_location()) == 0) {
6147 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6149 XMLNode &before = loc->get_state();
6151 _session->set_session_extents ( start, end );
6153 XMLNode &after = loc->get_state();
6155 begin_reversible_command (_("set session start/end from selection"));
6157 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6159 commit_reversible_command ();
6164 Editor::set_punch_from_region ()
6166 framepos_t start, end;
6167 if (!get_selection_extents ( start, end))
6170 set_punch_range (start, end, _("set punch range from region"));
6174 Editor::pitch_shift_region ()
6176 RegionSelection rs = get_regions_from_selection_and_entered ();
6178 RegionSelection audio_rs;
6179 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6180 if (dynamic_cast<AudioRegionView*> (*i)) {
6181 audio_rs.push_back (*i);
6185 if (audio_rs.empty()) {
6189 pitch_shift (audio_rs, 1.2);
6193 Editor::transpose_region ()
6195 RegionSelection rs = get_regions_from_selection_and_entered ();
6197 list<MidiRegionView*> midi_region_views;
6198 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6199 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6201 midi_region_views.push_back (mrv);
6206 int const r = d.run ();
6207 if (r != RESPONSE_ACCEPT) {
6211 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6212 (*i)->midi_region()->transpose (d.semitones ());
6217 Editor::set_tempo_from_region ()
6219 RegionSelection rs = get_regions_from_selection_and_entered ();
6221 if (!_session || rs.empty()) {
6225 RegionView* rv = rs.front();
6227 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6231 Editor::use_range_as_bar ()
6233 framepos_t start, end;
6234 if (get_edit_op_range (start, end)) {
6235 define_one_bar (start, end);
6240 Editor::define_one_bar (framepos_t start, framepos_t end)
6242 framepos_t length = end - start;
6244 const Meter& m (_session->tempo_map().meter_at (start));
6246 /* length = 1 bar */
6248 /* now we want frames per beat.
6249 we have frames per bar, and beats per bar, so ...
6252 /* XXXX METER MATH */
6254 double frames_per_beat = length / m.divisions_per_bar();
6256 /* beats per minute = */
6258 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6260 /* now decide whether to:
6262 (a) set global tempo
6263 (b) add a new tempo marker
6267 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6269 bool do_global = false;
6271 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6273 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6274 at the start, or create a new marker
6277 vector<string> options;
6278 options.push_back (_("Cancel"));
6279 options.push_back (_("Add new marker"));
6280 options.push_back (_("Set global tempo"));
6283 _("Define one bar"),
6284 _("Do you want to set the global tempo or add a new tempo marker?"),
6288 c.set_default_response (2);
6304 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6305 if the marker is at the region starter, change it, otherwise add
6310 begin_reversible_command (_("set tempo from region"));
6311 XMLNode& before (_session->tempo_map().get_state());
6314 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6315 } else if (t.frame() == start) {
6316 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6318 Timecode::BBT_Time bbt;
6319 _session->tempo_map().bbt_time (start, bbt);
6320 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6323 XMLNode& after (_session->tempo_map().get_state());
6325 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6326 commit_reversible_command ();
6330 Editor::split_region_at_transients ()
6332 AnalysisFeatureList positions;
6334 RegionSelection rs = get_regions_from_selection_and_entered ();
6336 if (!_session || rs.empty()) {
6340 begin_reversible_command (_("split regions"));
6342 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6344 RegionSelection::iterator tmp;
6349 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6351 if (ar && (ar->get_transients (positions) == 0)) {
6352 split_region_at_points ((*i)->region(), positions, true);
6359 commit_reversible_command ();
6364 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6366 bool use_rhythmic_rodent = false;
6368 boost::shared_ptr<Playlist> pl = r->playlist();
6370 list<boost::shared_ptr<Region> > new_regions;
6376 if (positions.empty()) {
6381 if (positions.size() > 20 && can_ferret) {
6382 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);
6383 MessageDialog msg (msgstr,
6386 Gtk::BUTTONS_OK_CANCEL);
6389 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6390 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6392 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6395 msg.set_title (_("Excessive split?"));
6398 int response = msg.run();
6404 case RESPONSE_APPLY:
6405 use_rhythmic_rodent = true;
6412 if (use_rhythmic_rodent) {
6413 show_rhythm_ferret ();
6417 AnalysisFeatureList::const_iterator x;
6419 pl->clear_changes ();
6420 pl->clear_owned_changes ();
6422 x = positions.begin();
6424 if (x == positions.end()) {
6429 pl->remove_region (r);
6433 while (x != positions.end()) {
6435 /* deal with positons that are out of scope of present region bounds */
6436 if (*x <= 0 || *x > r->length()) {
6441 /* file start = original start + how far we from the initial position ?
6444 framepos_t file_start = r->start() + pos;
6446 /* length = next position - current position
6449 framepos_t len = (*x) - pos;
6451 /* XXX we do we really want to allow even single-sample regions?
6452 shouldn't we have some kind of lower limit on region size?
6461 if (RegionFactory::region_name (new_name, r->name())) {
6465 /* do NOT announce new regions 1 by one, just wait till they are all done */
6469 plist.add (ARDOUR::Properties::start, file_start);
6470 plist.add (ARDOUR::Properties::length, len);
6471 plist.add (ARDOUR::Properties::name, new_name);
6472 plist.add (ARDOUR::Properties::layer, 0);
6474 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6475 /* because we set annouce to false, manually add the new region to the
6478 RegionFactory::map_add (nr);
6480 pl->add_region (nr, r->position() + pos);
6483 new_regions.push_front(nr);
6492 RegionFactory::region_name (new_name, r->name());
6494 /* Add the final region */
6497 plist.add (ARDOUR::Properties::start, r->start() + pos);
6498 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6499 plist.add (ARDOUR::Properties::name, new_name);
6500 plist.add (ARDOUR::Properties::layer, 0);
6502 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6503 /* because we set annouce to false, manually add the new region to the
6506 RegionFactory::map_add (nr);
6507 pl->add_region (nr, r->position() + pos);
6510 new_regions.push_front(nr);
6515 /* We might have removed regions, which alters other regions' layering_index,
6516 so we need to do a recursive diff here.
6518 vector<Command*> cmds;
6520 _session->add_commands (cmds);
6522 _session->add_command (new StatefulDiffCommand (pl));
6526 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6527 set_selected_regionview_from_region_list ((*i), Selection::Add);
6533 Editor::place_transient()
6539 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6545 framepos_t where = get_preferred_edit_position();
6547 begin_reversible_command (_("place transient"));
6549 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6550 framepos_t position = (*r)->region()->position();
6551 (*r)->region()->add_transient(where - position);
6554 commit_reversible_command ();
6558 Editor::remove_transient(ArdourCanvas::Item* item)
6564 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6567 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6568 _arv->remove_transient (*(float*) _line->get_data ("position"));
6572 Editor::snap_regions_to_grid ()
6574 list <boost::shared_ptr<Playlist > > used_playlists;
6576 RegionSelection rs = get_regions_from_selection_and_entered ();
6578 if (!_session || rs.empty()) {
6582 begin_reversible_command (_("snap regions to grid"));
6584 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6586 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6588 if (!pl->frozen()) {
6589 /* we haven't seen this playlist before */
6591 /* remember used playlists so we can thaw them later */
6592 used_playlists.push_back(pl);
6596 framepos_t start_frame = (*r)->region()->first_frame ();
6597 snap_to (start_frame);
6598 (*r)->region()->set_position (start_frame);
6601 while (used_playlists.size() > 0) {
6602 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6604 used_playlists.pop_front();
6607 commit_reversible_command ();
6611 Editor::close_region_gaps ()
6613 list <boost::shared_ptr<Playlist > > used_playlists;
6615 RegionSelection rs = get_regions_from_selection_and_entered ();
6617 if (!_session || rs.empty()) {
6621 Dialog dialog (_("Close Region Gaps"));
6624 table.set_spacings (12);
6625 table.set_border_width (12);
6626 Label* l = manage (left_aligned_label (_("Crossfade length")));
6627 table.attach (*l, 0, 1, 0, 1);
6629 SpinButton spin_crossfade (1, 0);
6630 spin_crossfade.set_range (0, 15);
6631 spin_crossfade.set_increments (1, 1);
6632 spin_crossfade.set_value (5);
6633 table.attach (spin_crossfade, 1, 2, 0, 1);
6635 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6637 l = manage (left_aligned_label (_("Pull-back length")));
6638 table.attach (*l, 0, 1, 1, 2);
6640 SpinButton spin_pullback (1, 0);
6641 spin_pullback.set_range (0, 100);
6642 spin_pullback.set_increments (1, 1);
6643 spin_pullback.set_value(30);
6644 table.attach (spin_pullback, 1, 2, 1, 2);
6646 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6648 dialog.get_vbox()->pack_start (table);
6649 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6650 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6653 if (dialog.run () == RESPONSE_CANCEL) {
6657 framepos_t crossfade_len = spin_crossfade.get_value();
6658 framepos_t pull_back_frames = spin_pullback.get_value();
6660 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6661 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6663 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6665 begin_reversible_command (_("close region gaps"));
6668 boost::shared_ptr<Region> last_region;
6670 rs.sort_by_position_and_track();
6672 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6674 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6676 if (!pl->frozen()) {
6677 /* we haven't seen this playlist before */
6679 /* remember used playlists so we can thaw them later */
6680 used_playlists.push_back(pl);
6684 framepos_t position = (*r)->region()->position();
6686 if (idx == 0 || position < last_region->position()){
6687 last_region = (*r)->region();
6692 (*r)->region()->trim_front( (position - pull_back_frames));
6693 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6695 last_region = (*r)->region();
6700 while (used_playlists.size() > 0) {
6701 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6703 used_playlists.pop_front();
6706 commit_reversible_command ();
6710 Editor::tab_to_transient (bool forward)
6712 AnalysisFeatureList positions;
6714 RegionSelection rs = get_regions_from_selection_and_entered ();
6720 framepos_t pos = _session->audible_frame ();
6722 if (!selection->tracks.empty()) {
6724 /* don't waste time searching for transients in duplicate playlists.
6727 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6729 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6731 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6734 boost::shared_ptr<Track> tr = rtv->track();
6736 boost::shared_ptr<Playlist> pl = tr->playlist ();
6738 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6741 positions.push_back (result);
6754 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6755 (*r)->region()->get_transients (positions);
6759 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6762 AnalysisFeatureList::iterator x;
6764 for (x = positions.begin(); x != positions.end(); ++x) {
6770 if (x != positions.end ()) {
6771 _session->request_locate (*x);
6775 AnalysisFeatureList::reverse_iterator x;
6777 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6783 if (x != positions.rend ()) {
6784 _session->request_locate (*x);
6790 Editor::playhead_forward_to_grid ()
6796 framepos_t pos = playhead_cursor->current_frame ();
6797 if (pos < max_framepos - 1) {
6799 snap_to_internal (pos, RoundUpAlways, false);
6800 _session->request_locate (pos);
6806 Editor::playhead_backward_to_grid ()
6812 framepos_t pos = playhead_cursor->current_frame ();
6815 snap_to_internal (pos, RoundDownAlways, false);
6816 _session->request_locate (pos);
6821 Editor::set_track_height (Height h)
6823 TrackSelection& ts (selection->tracks);
6825 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6826 (*x)->set_height_enum (h);
6831 Editor::toggle_tracks_active ()
6833 TrackSelection& ts (selection->tracks);
6835 bool target = false;
6841 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6842 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6846 target = !rtv->_route->active();
6849 rtv->_route->set_active (target, this);
6855 Editor::remove_tracks ()
6857 /* this will delete GUI objects that may be the subject of an event
6858 handler in which this method is called. Defer actual deletion to the
6859 next idle callback, when all event handling is finished.
6861 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
6865 Editor::idle_remove_tracks ()
6868 return false; /* do not call again */
6872 Editor::_remove_tracks ()
6874 TrackSelection& ts (selection->tracks);
6880 vector<string> choices;
6884 const char* trackstr;
6886 vector<boost::shared_ptr<Route> > routes;
6887 bool special_bus = false;
6889 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6890 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6894 if (rtv->is_track()) {
6899 routes.push_back (rtv->_route);
6901 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6906 if (special_bus && !Config->get_allow_special_bus_removal()) {
6907 MessageDialog msg (_("That would be bad news ...."),
6911 msg.set_secondary_text (string_compose (_(
6912 "Removing the master or monitor bus is such a bad idea\n\
6913 that %1 is not going to allow it.\n\
6915 If you really want to do this sort of thing\n\
6916 edit your ardour.rc file to set the\n\
6917 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6924 if (ntracks + nbusses == 0) {
6928 trackstr = P_("track", "tracks", ntracks);
6929 busstr = P_("bus", "busses", nbusses);
6933 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6934 "(You may also lose the playlists associated with the %2)\n\n"
6935 "This action cannot be undone, and the session file will be overwritten!"),
6936 ntracks, trackstr, nbusses, busstr);
6938 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6939 "(You may also lose the playlists associated with the %2)\n\n"
6940 "This action cannot be undone, and the session file will be overwritten!"),
6943 } else if (nbusses) {
6944 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6945 "This action cannot be undone, and the session file will be overwritten"),
6949 choices.push_back (_("No, do nothing."));
6950 if (ntracks + nbusses > 1) {
6951 choices.push_back (_("Yes, remove them."));
6953 choices.push_back (_("Yes, remove it."));
6958 title = string_compose (_("Remove %1"), trackstr);
6960 title = string_compose (_("Remove %1"), busstr);
6963 Choice prompter (title, prompt, choices);
6965 if (prompter.run () != 1) {
6970 Session::StateProtector sp (_session);
6971 DisplaySuspender ds;
6972 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6973 _session->remove_route (*x);
6979 Editor::do_insert_time ()
6981 if (selection->tracks.empty()) {
6985 InsertTimeDialog d (*this);
6986 int response = d.run ();
6988 if (response != RESPONSE_OK) {
6992 if (d.distance() == 0) {
6996 InsertTimeOption opt = d.intersected_region_action ();
6999 get_preferred_edit_position(),
7005 d.move_glued_markers(),
7006 d.move_locked_markers(),
7012 Editor::insert_time (
7013 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7014 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7018 if (Config->get_edit_mode() == Lock) {
7021 bool commit = false;
7022 begin_reversible_command (_("insert time"));
7024 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7026 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7030 /* don't operate on any playlist more than once, which could
7031 * happen if "all playlists" is enabled, but there is more
7032 * than 1 track using playlists "from" a given track.
7035 set<boost::shared_ptr<Playlist> > pl;
7037 if (all_playlists) {
7038 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7040 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7041 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7046 if ((*x)->playlist ()) {
7047 pl.insert ((*x)->playlist ());
7051 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7053 (*i)->clear_changes ();
7054 (*i)->clear_owned_changes ();
7056 if (opt == SplitIntersected) {
7060 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7062 vector<Command*> cmds;
7064 _session->add_commands (cmds);
7066 _session->add_command (new StatefulDiffCommand (*i));
7071 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7073 rtav->route ()->shift (pos, frames);
7080 XMLNode& before (_session->locations()->get_state());
7081 Locations::LocationList copy (_session->locations()->list());
7083 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7085 Locations::LocationList::const_iterator tmp;
7087 bool const was_locked = (*i)->locked ();
7088 if (locked_markers_too) {
7092 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7094 if ((*i)->start() >= pos) {
7095 (*i)->set_start ((*i)->start() + frames);
7096 if (!(*i)->is_mark()) {
7097 (*i)->set_end ((*i)->end() + frames);
7110 XMLNode& after (_session->locations()->get_state());
7111 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7117 _session->tempo_map().insert_time (pos, frames);
7121 commit_reversible_command ();
7123 abort_reversible_command ();
7127 Editor::do_cut_time ()
7129 if (selection->tracks.empty()) {
7133 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7134 ArdourDialog d (*this, _("Cut Time"));
7135 VButtonBox button_box;
7138 CheckButton glue_button (_("Move Glued Regions")); glue_button.set_active();
7139 CheckButton marker_button (_("Move Markers")); marker_button.set_active();
7140 CheckButton tempo_button (_("Move Tempo & Meters")); tempo_button.set_active();
7141 AudioClock clock ("cutTimeClock", true, "", true, false, true, false);
7145 clock.set_session (_session);
7146 clock.set_bbt_reference (pos);
7148 clock_box.pack_start (clock, false, true);
7150 option_box.set_spacing (6);
7151 option_box.pack_start (button_box, false, false);
7152 option_box.pack_start (glue_button, false, false);
7153 option_box.pack_start (marker_button, false, false);
7154 option_box.pack_start (tempo_button, false, false);
7156 d.get_vbox()->set_border_width (12);
7157 d.get_vbox()->pack_start (clock_box, false, false);
7158 d.get_vbox()->pack_start (option_box, false, false);
7162 glue_button.show ();
7165 marker_button.show ();
7166 tempo_button.show ();
7168 d.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
7169 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
7172 int response = d.run ();
7174 if (response != RESPONSE_OK) {
7178 framecnt_t distance = clock.current_duration (pos);
7180 if (distance == 0) {
7184 cut_time (pos, distance, SplitIntersected, glue_button.get_active(), marker_button.get_active(), tempo_button.get_active());
7188 Editor::cut_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7189 bool ignore_music_glue, bool markers_too, bool tempo_too)
7191 if (Config->get_edit_mode() == Lock) {
7192 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7195 bool commit = false;
7196 begin_reversible_command (_("cut time"));
7198 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7200 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7204 XMLNode &before = pl->get_state();
7206 std::list<AudioRange> rl;
7207 AudioRange ar(pos, pos+frames, 0);
7210 pl->shift (pos, -frames, true, ignore_music_glue);
7212 XMLNode &after = pl->get_state();
7214 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7219 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7221 rtav->route ()->shift (pos, -frames);
7225 std::list<Location*> loc_kill_list;
7230 XMLNode& before (_session->locations()->get_state());
7231 Locations::LocationList copy (_session->locations()->list());
7233 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7235 if (!(*i)->is_mark()) { //range; have to handle both start and end
7236 if ((*i)->end() >= pos
7237 && (*i)->end() < pos+frames
7238 && (*i)->start() >= pos
7239 && (*i)->end() < pos+frames) { //range is completely enclosed; kill it
7241 loc_kill_list.push_back(*i);
7242 } else { //ony start or end is included, try to do the right thing
7243 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7244 (*i)->set_end (pos); //bring the end to the cut
7246 } else if ((*i)->end() >= pos) {
7247 (*i)->set_end ((*i)->end()-frames); //slip the end marker back
7250 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7251 (*i)->set_start (pos); //bring the start marker to the beginning of the cut
7253 } else if ((*i)->start() >= pos) {
7254 (*i)->set_start ((*i)->start() -frames); //slip the end marker back
7258 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7259 loc_kill_list.push_back(*i);
7261 } else if ((*i)->start() >= pos) {
7262 (*i)->set_start ((*i)->start() -frames);
7267 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7268 _session->locations()->remove( *i );
7272 XMLNode& after (_session->locations()->get_state());
7273 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7279 XMLNode& before (_session->tempo_map().get_state());
7281 if (_session->tempo_map().cut_time (pos, frames) ) {
7282 XMLNode& after (_session->tempo_map().get_state());
7283 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7289 commit_reversible_command ();
7291 abort_reversible_command ();
7296 Editor::fit_selection ()
7298 if (!selection->tracks.empty()) {
7299 fit_tracks (selection->tracks);
7303 /* no selected tracks - use tracks with selected regions */
7305 if (!selection->regions.empty()) {
7306 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7307 tvl.push_back (&(*r)->get_time_axis_view ());
7313 } else if (internal_editing()) {
7314 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7317 if (entered_track) {
7318 tvl.push_back (entered_track);
7327 Editor::fit_tracks (TrackViewList & tracks)
7329 if (tracks.empty()) {
7333 uint32_t child_heights = 0;
7334 int visible_tracks = 0;
7336 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7338 if (!(*t)->marked_for_display()) {
7342 child_heights += (*t)->effective_height() - (*t)->current_height();
7346 /* compute the per-track height from:
7348 total canvas visible height -
7349 height that will be taken by visible children of selected
7350 tracks - height of the ruler/hscroll area
7352 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7353 double first_y_pos = DBL_MAX;
7355 if (h < TimeAxisView::preset_height (HeightSmall)) {
7356 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7357 /* too small to be displayed */
7361 undo_visual_stack.push_back (current_visual_state (true));
7362 PBD::Unwinder<bool> nsv (no_save_visual, true);
7364 /* build a list of all tracks, including children */
7367 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7369 TimeAxisView::Children c = (*i)->get_child_list ();
7370 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7371 all.push_back (j->get());
7376 // find selection range.
7377 // if someone knows how to user TrackViewList::iterator for this
7379 int selected_top = -1;
7380 int selected_bottom = -1;
7382 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7383 if ((*t)->marked_for_display ()) {
7384 if (tracks.contains(*t)) {
7385 if (selected_top == -1) {
7388 selected_bottom = i;
7394 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7395 if ((*t)->marked_for_display ()) {
7396 if (tracks.contains(*t)) {
7397 (*t)->set_height (h);
7398 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7400 if (i > selected_top && i < selected_bottom) {
7401 hide_track_in_display (*t);
7408 set the controls_layout height now, because waiting for its size
7409 request signal handler will cause the vertical adjustment setting to fail
7412 controls_layout.property_height () = _full_canvas_height;
7413 vertical_adjustment.set_value (first_y_pos);
7415 redo_visual_stack.push_back (current_visual_state (true));
7417 visible_tracks_selector.set_text (_("Sel"));
7421 Editor::save_visual_state (uint32_t n)
7423 while (visual_states.size() <= n) {
7424 visual_states.push_back (0);
7427 if (visual_states[n] != 0) {
7428 delete visual_states[n];
7431 visual_states[n] = current_visual_state (true);
7436 Editor::goto_visual_state (uint32_t n)
7438 if (visual_states.size() <= n) {
7442 if (visual_states[n] == 0) {
7446 use_visual_state (*visual_states[n]);
7450 Editor::start_visual_state_op (uint32_t n)
7452 save_visual_state (n);
7454 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7456 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7457 pup->set_text (buf);
7462 Editor::cancel_visual_state_op (uint32_t n)
7464 goto_visual_state (n);
7468 Editor::toggle_region_mute ()
7470 if (_ignore_region_action) {
7474 RegionSelection rs = get_regions_from_selection_and_entered ();
7480 if (rs.size() > 1) {
7481 begin_reversible_command (_("mute regions"));
7483 begin_reversible_command (_("mute region"));
7486 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7488 (*i)->region()->playlist()->clear_changes ();
7489 (*i)->region()->set_muted (!(*i)->region()->muted ());
7490 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7494 commit_reversible_command ();
7498 Editor::combine_regions ()
7500 /* foreach track with selected regions, take all selected regions
7501 and join them into a new region containing the subregions (as a
7505 typedef set<RouteTimeAxisView*> RTVS;
7508 if (selection->regions.empty()) {
7512 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7513 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7516 tracks.insert (rtv);
7520 begin_reversible_command (_("combine regions"));
7522 vector<RegionView*> new_selection;
7524 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7527 if ((rv = (*i)->combine_regions ()) != 0) {
7528 new_selection.push_back (rv);
7532 selection->clear_regions ();
7533 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7534 selection->add (*i);
7537 commit_reversible_command ();
7541 Editor::uncombine_regions ()
7543 typedef set<RouteTimeAxisView*> RTVS;
7546 if (selection->regions.empty()) {
7550 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7551 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7554 tracks.insert (rtv);
7558 begin_reversible_command (_("uncombine regions"));
7560 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7561 (*i)->uncombine_regions ();
7564 commit_reversible_command ();
7568 Editor::toggle_midi_input_active (bool flip_others)
7571 boost::shared_ptr<RouteList> rl (new RouteList);
7573 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7574 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7580 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7583 rl->push_back (rtav->route());
7584 onoff = !mt->input_active();
7588 _session->set_exclusive_input_active (rl, onoff, flip_others);
7595 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7597 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7598 lock_dialog->get_vbox()->pack_start (*padlock);
7600 ArdourButton* b = manage (new ArdourButton);
7601 b->set_name ("lock button");
7602 b->set_text (_("Click to unlock"));
7603 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7604 lock_dialog->get_vbox()->pack_start (*b);
7606 lock_dialog->get_vbox()->show_all ();
7607 lock_dialog->set_size_request (200, 200);
7611 /* The global menu bar continues to be accessible to applications
7612 with modal dialogs, which means that we need to desensitize
7613 all items in the menu bar. Since those items are really just
7614 proxies for actions, that means disabling all actions.
7616 ActionManager::disable_all_actions ();
7618 lock_dialog->present ();
7624 lock_dialog->hide ();
7627 ActionManager::pop_action_state ();
7630 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7631 start_lock_event_timing ();
7636 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7638 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7642 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7644 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7645 Gtkmm2ext::UI::instance()->flush_pending ();
7649 Editor::bring_all_sources_into_session ()
7656 ArdourDialog w (_("Moving embedded files into session folder"));
7657 w.get_vbox()->pack_start (msg);
7660 /* flush all pending GUI events because we're about to start copying
7664 Gtkmm2ext::UI::instance()->flush_pending ();
7668 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));