2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
100 #include "transform_dialog.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
112 /***********************************************************************
114 ***********************************************************************/
117 Editor::undo (uint32_t n)
119 if (_drags->active ()) {
125 if (_session->undo_depth() == 0) {
126 undo_action->set_sensitive(false);
128 redo_action->set_sensitive(true);
129 begin_selection_op_history ();
134 Editor::redo (uint32_t n)
136 if (_drags->active ()) {
142 if (_session->redo_depth() == 0) {
143 redo_action->set_sensitive(false);
145 undo_action->set_sensitive(true);
146 begin_selection_op_history ();
151 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
155 RegionSelection pre_selected_regions = selection->regions;
156 bool working_on_selection = !pre_selected_regions.empty();
158 list<boost::shared_ptr<Playlist> > used_playlists;
159 list<RouteTimeAxisView*> used_trackviews;
161 if (regions.empty()) {
165 begin_reversible_command (_("split"));
167 // if splitting a single region, and snap-to is using
168 // region boundaries, don't pay attention to them
170 if (regions.size() == 1) {
171 switch (_snap_type) {
172 case SnapToRegionStart:
173 case SnapToRegionSync:
174 case SnapToRegionEnd:
183 EditorFreeze(); /* Emit Signal */
186 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
188 RegionSelection::iterator tmp;
190 /* XXX this test needs to be more complicated, to make sure we really
191 have something to split.
194 if (!(*a)->region()->covers (where)) {
202 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
210 /* we haven't seen this playlist before */
212 /* remember used playlists so we can thaw them later */
213 used_playlists.push_back(pl);
215 TimeAxisView& tv = (*a)->get_time_axis_view();
216 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
218 used_trackviews.push_back (rtv);
225 pl->clear_changes ();
226 pl->split_region ((*a)->region(), where);
227 _session->add_command (new StatefulDiffCommand (pl));
233 latest_regionviews.clear ();
235 vector<sigc::connection> region_added_connections;
237 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
238 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
241 while (used_playlists.size() > 0) {
242 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
244 used_playlists.pop_front();
247 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
252 EditorThaw(); /* Emit Signal */
255 if (working_on_selection) {
256 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
258 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
259 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
260 /* There are three classes of regions that we might want selected after
261 splitting selected regions:
262 - regions selected before the split operation, and unaffected by it
263 - newly-created regions before the split
264 - newly-created regions after the split
267 if (rsas & Existing) {
268 // region selections that existed before the split.
269 selection->add ( pre_selected_regions );
272 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
273 if ((*ri)->region()->position() < where) {
274 // new regions created before the split
275 if (rsas & NewlyCreatedLeft) {
276 selection->add (*ri);
279 // new regions created after the split
280 if (rsas & NewlyCreatedRight) {
281 selection->add (*ri);
285 _ignore_follow_edits = false;
287 _ignore_follow_edits = true;
288 if( working_on_selection ) {
289 selection->add (latest_regionviews); //these are the new regions created after the split
291 _ignore_follow_edits = false;
294 commit_reversible_command ();
297 /** Move one extreme of the current range selection. If more than one range is selected,
298 * the start of the earliest range or the end of the latest range is moved.
300 * @param move_end true to move the end of the current range selection, false to move
302 * @param next true to move the extreme to the next region boundary, false to move to
306 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
308 if (selection->time.start() == selection->time.end_frame()) {
312 framepos_t start = selection->time.start ();
313 framepos_t end = selection->time.end_frame ();
315 /* the position of the thing we may move */
316 framepos_t pos = move_end ? end : start;
317 int dir = next ? 1 : -1;
319 /* so we don't find the current region again */
320 if (dir > 0 || pos > 0) {
324 framepos_t const target = get_region_boundary (pos, dir, true, false);
339 begin_reversible_command (_("alter selection"));
340 selection->set_preserving_all_ranges (start, end);
341 commit_reversible_command ();
345 Editor::nudge_forward_release (GdkEventButton* ev)
347 if (ev->state & Keyboard::PrimaryModifier) {
348 nudge_forward (false, true);
350 nudge_forward (false, false);
356 Editor::nudge_backward_release (GdkEventButton* ev)
358 if (ev->state & Keyboard::PrimaryModifier) {
359 nudge_backward (false, true);
361 nudge_backward (false, false);
368 Editor::nudge_forward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions forward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
393 r->set_position (r->position() + distance);
394 _session->add_command (new StatefulDiffCommand (r));
397 commit_reversible_command ();
400 } else if (!force_playhead && !selection->markers.empty()) {
404 begin_reversible_command (_("nudge location forward"));
406 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
408 Location* loc = find_location_from_marker ((*i), is_start);
412 XMLNode& before (loc->get_state());
415 distance = get_nudge_distance (loc->start(), next_distance);
417 distance = next_distance;
419 if (max_framepos - distance > loc->start() + loc->length()) {
420 loc->set_start (loc->start() + distance);
422 loc->set_start (max_framepos - loc->length());
425 distance = get_nudge_distance (loc->end(), next_distance);
427 distance = next_distance;
429 if (max_framepos - distance > loc->end()) {
430 loc->set_end (loc->end() + distance);
432 loc->set_end (max_framepos);
435 XMLNode& after (loc->get_state());
436 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
440 commit_reversible_command ();
443 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
444 _session->request_locate (playhead_cursor->current_frame () + distance);
449 Editor::nudge_backward (bool next, bool force_playhead)
452 framepos_t next_distance;
458 RegionSelection rs = get_regions_from_selection_and_entered ();
460 if (!force_playhead && !rs.empty()) {
462 begin_reversible_command (_("nudge regions backward"));
464 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
465 boost::shared_ptr<Region> r ((*i)->region());
467 distance = get_nudge_distance (r->position(), next_distance);
470 distance = next_distance;
475 if (r->position() > distance) {
476 r->set_position (r->position() - distance);
480 _session->add_command (new StatefulDiffCommand (r));
483 commit_reversible_command ();
485 } else if (!force_playhead && !selection->markers.empty()) {
489 begin_reversible_command (_("nudge location forward"));
491 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
493 Location* loc = find_location_from_marker ((*i), is_start);
497 XMLNode& before (loc->get_state());
500 distance = get_nudge_distance (loc->start(), next_distance);
502 distance = next_distance;
504 if (distance < loc->start()) {
505 loc->set_start (loc->start() - distance);
510 distance = get_nudge_distance (loc->end(), next_distance);
513 distance = next_distance;
516 if (distance < loc->end() - loc->length()) {
517 loc->set_end (loc->end() - distance);
519 loc->set_end (loc->length());
523 XMLNode& after (loc->get_state());
524 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
528 commit_reversible_command ();
532 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
534 if (playhead_cursor->current_frame () > distance) {
535 _session->request_locate (playhead_cursor->current_frame () - distance);
537 _session->goto_start();
543 Editor::nudge_forward_capture_offset ()
545 RegionSelection rs = get_regions_from_selection_and_entered ();
547 if (!_session || rs.empty()) {
551 begin_reversible_command (_("nudge forward"));
553 framepos_t const distance = _session->worst_output_latency();
555 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
556 boost::shared_ptr<Region> r ((*i)->region());
559 r->set_position (r->position() + distance);
560 _session->add_command(new StatefulDiffCommand (r));
563 commit_reversible_command ();
567 Editor::nudge_backward_capture_offset ()
569 RegionSelection rs = get_regions_from_selection_and_entered ();
571 if (!_session || rs.empty()) {
575 begin_reversible_command (_("nudge backward"));
577 framepos_t const distance = _session->worst_output_latency();
579 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
580 boost::shared_ptr<Region> r ((*i)->region());
584 if (r->position() > distance) {
585 r->set_position (r->position() - distance);
589 _session->add_command(new StatefulDiffCommand (r));
592 commit_reversible_command ();
595 struct RegionSelectionPositionSorter {
596 bool operator() (RegionView* a, RegionView* b) {
597 return a->region()->position() < b->region()->position();
602 Editor::sequence_regions ()
605 framepos_t r_end_prev;
613 RegionSelection rs = get_regions_from_selection_and_entered ();
614 rs.sort(RegionSelectionPositionSorter());
618 begin_reversible_command (_("sequence regions"));
619 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
620 boost::shared_ptr<Region> r ((*i)->region());
628 if(r->position_locked())
635 r->set_position(r_end_prev);
638 _session->add_command (new StatefulDiffCommand (r));
640 r_end=r->position() + r->length();
644 commit_reversible_command ();
652 Editor::move_to_start ()
654 _session->goto_start ();
658 Editor::move_to_end ()
661 _session->request_locate (_session->current_end_frame());
665 Editor::build_region_boundary_cache ()
668 vector<RegionPoint> interesting_points;
669 boost::shared_ptr<Region> r;
670 TrackViewList tracks;
673 region_boundary_cache.clear ();
679 switch (_snap_type) {
680 case SnapToRegionStart:
681 interesting_points.push_back (Start);
683 case SnapToRegionEnd:
684 interesting_points.push_back (End);
686 case SnapToRegionSync:
687 interesting_points.push_back (SyncPoint);
689 case SnapToRegionBoundary:
690 interesting_points.push_back (Start);
691 interesting_points.push_back (End);
694 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
695 abort(); /*NOTREACHED*/
699 TimeAxisView *ontrack = 0;
702 if (!selection->tracks.empty()) {
703 tlist = selection->tracks.filter_to_unique_playlists ();
705 tlist = track_views.filter_to_unique_playlists ();
708 while (pos < _session->current_end_frame() && !at_end) {
711 framepos_t lpos = max_framepos;
713 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
715 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
716 if (*p == interesting_points.back()) {
719 /* move to next point type */
725 rpos = r->first_frame();
729 rpos = r->last_frame();
733 rpos = r->sync_position ();
741 RouteTimeAxisView *rtav;
743 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
744 if (rtav->track() != 0) {
745 speed = rtav->track()->speed();
749 rpos = track_frame_to_session_frame (rpos, speed);
755 /* prevent duplicates, but we don't use set<> because we want to be able
759 vector<framepos_t>::iterator ri;
761 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
767 if (ri == region_boundary_cache.end()) {
768 region_boundary_cache.push_back (rpos);
775 /* finally sort to be sure that the order is correct */
777 sort (region_boundary_cache.begin(), region_boundary_cache.end());
780 boost::shared_ptr<Region>
781 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
783 TrackViewList::iterator i;
784 framepos_t closest = max_framepos;
785 boost::shared_ptr<Region> ret;
789 framepos_t track_frame;
790 RouteTimeAxisView *rtav;
792 for (i = tracks.begin(); i != tracks.end(); ++i) {
795 boost::shared_ptr<Region> r;
798 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
799 if (rtav->track()!=0)
800 track_speed = rtav->track()->speed();
803 track_frame = session_frame_to_track_frame(frame, track_speed);
805 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
811 rpos = r->first_frame ();
815 rpos = r->last_frame ();
819 rpos = r->sync_position ();
823 // rpos is a "track frame", converting it to "_session frame"
824 rpos = track_frame_to_session_frame(rpos, track_speed);
827 distance = rpos - frame;
829 distance = frame - rpos;
832 if (distance < closest) {
844 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
846 framecnt_t distance = max_framepos;
847 framepos_t current_nearest = -1;
849 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
850 framepos_t contender;
853 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
859 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
863 d = ::llabs (pos - contender);
866 current_nearest = contender;
871 return current_nearest;
875 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
880 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
882 if (!selection->tracks.empty()) {
884 target = find_next_region_boundary (pos, dir, selection->tracks);
888 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
889 get_onscreen_tracks (tvl);
890 target = find_next_region_boundary (pos, dir, tvl);
892 target = find_next_region_boundary (pos, dir, track_views);
898 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
899 get_onscreen_tracks (tvl);
900 target = find_next_region_boundary (pos, dir, tvl);
902 target = find_next_region_boundary (pos, dir, track_views);
910 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
912 framepos_t pos = playhead_cursor->current_frame ();
919 // so we don't find the current region again..
920 if (dir > 0 || pos > 0) {
924 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
928 _session->request_locate (target);
932 Editor::cursor_to_next_region_boundary (bool with_selection)
934 cursor_to_region_boundary (with_selection, 1);
938 Editor::cursor_to_previous_region_boundary (bool with_selection)
940 cursor_to_region_boundary (with_selection, -1);
944 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
946 boost::shared_ptr<Region> r;
947 framepos_t pos = cursor->current_frame ();
953 TimeAxisView *ontrack = 0;
955 // so we don't find the current region again..
959 if (!selection->tracks.empty()) {
961 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
963 } else if (clicked_axisview) {
966 t.push_back (clicked_axisview);
968 r = find_next_region (pos, point, dir, t, &ontrack);
972 r = find_next_region (pos, point, dir, track_views, &ontrack);
981 pos = r->first_frame ();
985 pos = r->last_frame ();
989 pos = r->sync_position ();
994 RouteTimeAxisView *rtav;
996 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
997 if (rtav->track() != 0) {
998 speed = rtav->track()->speed();
1002 pos = track_frame_to_session_frame(pos, speed);
1004 if (cursor == playhead_cursor) {
1005 _session->request_locate (pos);
1007 cursor->set_position (pos);
1012 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1014 cursor_to_region_point (cursor, point, 1);
1018 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1020 cursor_to_region_point (cursor, point, -1);
1024 Editor::cursor_to_selection_start (EditorCursor *cursor)
1028 switch (mouse_mode) {
1030 if (!selection->regions.empty()) {
1031 pos = selection->regions.start();
1036 if (!selection->time.empty()) {
1037 pos = selection->time.start ();
1045 if (cursor == playhead_cursor) {
1046 _session->request_locate (pos);
1048 cursor->set_position (pos);
1053 Editor::cursor_to_selection_end (EditorCursor *cursor)
1057 switch (mouse_mode) {
1059 if (!selection->regions.empty()) {
1060 pos = selection->regions.end_frame();
1065 if (!selection->time.empty()) {
1066 pos = selection->time.end_frame ();
1074 if (cursor == playhead_cursor) {
1075 _session->request_locate (pos);
1077 cursor->set_position (pos);
1082 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1092 if (selection->markers.empty()) {
1096 if (!mouse_frame (mouse, ignored)) {
1100 add_location_mark (mouse);
1103 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1107 framepos_t pos = loc->start();
1109 // so we don't find the current region again..
1110 if (dir > 0 || pos > 0) {
1114 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1118 loc->move_to (target);
1122 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1124 selected_marker_to_region_boundary (with_selection, 1);
1128 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1130 selected_marker_to_region_boundary (with_selection, -1);
1134 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1136 boost::shared_ptr<Region> r;
1141 if (!_session || selection->markers.empty()) {
1145 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1149 TimeAxisView *ontrack = 0;
1153 // so we don't find the current region again..
1157 if (!selection->tracks.empty()) {
1159 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1163 r = find_next_region (pos, point, dir, track_views, &ontrack);
1172 pos = r->first_frame ();
1176 pos = r->last_frame ();
1180 pos = r->adjust_to_sync (r->first_frame());
1185 RouteTimeAxisView *rtav;
1187 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1188 if (rtav->track() != 0) {
1189 speed = rtav->track()->speed();
1193 pos = track_frame_to_session_frame(pos, speed);
1199 Editor::selected_marker_to_next_region_point (RegionPoint point)
1201 selected_marker_to_region_point (point, 1);
1205 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1207 selected_marker_to_region_point (point, -1);
1211 Editor::selected_marker_to_selection_start ()
1217 if (!_session || selection->markers.empty()) {
1221 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1225 switch (mouse_mode) {
1227 if (!selection->regions.empty()) {
1228 pos = selection->regions.start();
1233 if (!selection->time.empty()) {
1234 pos = selection->time.start ();
1246 Editor::selected_marker_to_selection_end ()
1252 if (!_session || selection->markers.empty()) {
1256 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1260 switch (mouse_mode) {
1262 if (!selection->regions.empty()) {
1263 pos = selection->regions.end_frame();
1268 if (!selection->time.empty()) {
1269 pos = selection->time.end_frame ();
1281 Editor::scroll_playhead (bool forward)
1283 framepos_t pos = playhead_cursor->current_frame ();
1284 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1287 if (pos == max_framepos) {
1291 if (pos < max_framepos - delta) {
1310 _session->request_locate (pos);
1314 Editor::cursor_align (bool playhead_to_edit)
1320 if (playhead_to_edit) {
1322 if (selection->markers.empty()) {
1326 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1329 /* move selected markers to playhead */
1331 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1334 Location* loc = find_location_from_marker (*i, ignored);
1336 if (loc->is_mark()) {
1337 loc->set_start (playhead_cursor->current_frame ());
1339 loc->set (playhead_cursor->current_frame (),
1340 playhead_cursor->current_frame () + loc->length());
1347 Editor::scroll_backward (float pages)
1349 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1350 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1353 if (leftmost_frame < cnt) {
1356 frame = leftmost_frame - cnt;
1359 reset_x_origin (frame);
1363 Editor::scroll_forward (float pages)
1365 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1366 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1369 if (max_framepos - cnt < leftmost_frame) {
1370 frame = max_framepos - cnt;
1372 frame = leftmost_frame + cnt;
1375 reset_x_origin (frame);
1379 Editor::scroll_tracks_down ()
1381 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1382 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1383 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1386 vertical_adjustment.set_value (vert_value);
1390 Editor::scroll_tracks_up ()
1392 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1396 Editor::scroll_tracks_down_line ()
1398 double vert_value = vertical_adjustment.get_value() + 60;
1400 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1401 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1404 vertical_adjustment.set_value (vert_value);
1408 Editor::scroll_tracks_up_line ()
1410 reset_y_origin (vertical_adjustment.get_value() - 60);
1414 Editor::scroll_down_one_track ()
1416 TrackViewList::reverse_iterator next = track_views.rend();
1417 std::pair<TimeAxisView*,double> res;
1418 const double top_of_trackviews = vertical_adjustment.get_value();
1420 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1421 if ((*t)->hidden()) {
1426 /* If this is the upper-most visible trackview, we want to display
1427 the one above it (next)
1430 res = (*t)->covers_y_position (top_of_trackviews);
1438 /* move to the track below the first one that covers the */
1440 if (next != track_views.rend()) {
1441 ensure_time_axis_view_is_visible (**next, true);
1449 Editor::scroll_up_one_track ()
1451 TrackViewList::iterator prev = track_views.end();
1452 std::pair<TimeAxisView*,double> res;
1453 double top_of_trackviews = vertical_adjustment.get_value ();
1455 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1457 if ((*t)->hidden()) {
1461 /* find the trackview at the top of the trackview group */
1462 res = (*t)->covers_y_position (top_of_trackviews);
1471 if (prev != track_views.end()) {
1472 ensure_time_axis_view_is_visible (**prev, true);
1482 Editor::tav_zoom_step (bool coarser)
1484 DisplaySuspender ds;
1488 if (selection->tracks.empty()) {
1491 ts = &selection->tracks;
1494 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1495 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1496 tv->step_height (coarser);
1501 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1503 DisplaySuspender ds;
1507 if (selection->tracks.empty() || force_all) {
1510 ts = &selection->tracks;
1513 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1514 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1515 uint32_t h = tv->current_height ();
1520 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1525 tv->set_height (h + 5);
1532 Editor::temporal_zoom_step (bool coarser)
1534 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1536 framecnt_t nspp = samples_per_pixel;
1544 temporal_zoom (nspp);
1548 Editor::temporal_zoom (framecnt_t fpp)
1554 framepos_t current_page = current_page_samples();
1555 framepos_t current_leftmost = leftmost_frame;
1556 framepos_t current_rightmost;
1557 framepos_t current_center;
1558 framepos_t new_page_size;
1559 framepos_t half_page_size;
1560 framepos_t leftmost_after_zoom = 0;
1562 bool in_track_canvas;
1566 if (fpp == samples_per_pixel) {
1570 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1571 // segfaults for lack of memory. If somebody decides this is not high enough I
1572 // believe it can be raisen to higher values but some limit must be in place.
1574 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1575 // all of which is used for the editor track displays. The whole day
1576 // would be 4147200000 samples, so 2592000 samples per pixel.
1578 nfpp = min (fpp, (framecnt_t) 2592000);
1579 nfpp = max ((framecnt_t) 1, nfpp);
1581 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1582 half_page_size = new_page_size / 2;
1584 switch (zoom_focus) {
1586 leftmost_after_zoom = current_leftmost;
1589 case ZoomFocusRight:
1590 current_rightmost = leftmost_frame + current_page;
1591 if (current_rightmost < new_page_size) {
1592 leftmost_after_zoom = 0;
1594 leftmost_after_zoom = current_rightmost - new_page_size;
1598 case ZoomFocusCenter:
1599 current_center = current_leftmost + (current_page/2);
1600 if (current_center < half_page_size) {
1601 leftmost_after_zoom = 0;
1603 leftmost_after_zoom = current_center - half_page_size;
1607 case ZoomFocusPlayhead:
1608 /* centre playhead */
1609 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1612 leftmost_after_zoom = 0;
1613 } else if (l > max_framepos) {
1614 leftmost_after_zoom = max_framepos - new_page_size;
1616 leftmost_after_zoom = (framepos_t) l;
1620 case ZoomFocusMouse:
1621 /* try to keep the mouse over the same point in the display */
1623 if (!mouse_frame (where, in_track_canvas)) {
1624 /* use playhead instead */
1625 where = playhead_cursor->current_frame ();
1627 if (where < half_page_size) {
1628 leftmost_after_zoom = 0;
1630 leftmost_after_zoom = where - half_page_size;
1635 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1638 leftmost_after_zoom = 0;
1639 } else if (l > max_framepos) {
1640 leftmost_after_zoom = max_framepos - new_page_size;
1642 leftmost_after_zoom = (framepos_t) l;
1649 /* try to keep the edit point in the same place */
1650 where = get_preferred_edit_position ();
1654 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1657 leftmost_after_zoom = 0;
1658 } else if (l > max_framepos) {
1659 leftmost_after_zoom = max_framepos - new_page_size;
1661 leftmost_after_zoom = (framepos_t) l;
1665 /* edit point not defined */
1672 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1674 reposition_and_zoom (leftmost_after_zoom, nfpp);
1678 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1680 /* this func helps make sure we leave a little space
1681 at each end of the editor so that the zoom doesn't fit the region
1682 precisely to the screen.
1685 GdkScreen* screen = gdk_screen_get_default ();
1686 const gint pixwidth = gdk_screen_get_width (screen);
1687 const gint mmwidth = gdk_screen_get_width_mm (screen);
1688 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1689 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1691 const framepos_t range = end - start;
1692 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1693 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1695 if (start > extra_samples) {
1696 start -= extra_samples;
1701 if (max_framepos - extra_samples > end) {
1702 end += extra_samples;
1709 Editor::temporal_zoom_region (bool both_axes)
1711 framepos_t start = max_framepos;
1713 set<TimeAxisView*> tracks;
1715 if ( !get_selection_extents(start, end) )
1718 calc_extra_zoom_edges (start, end);
1720 /* if we're zooming on both axes we need to save track heights etc.
1723 undo_visual_stack.push_back (current_visual_state (both_axes));
1725 PBD::Unwinder<bool> nsv (no_save_visual, true);
1727 temporal_zoom_by_frame (start, end);
1730 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1732 /* set visible track heights appropriately */
1734 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1735 (*t)->set_height (per_track_height);
1738 /* hide irrelevant tracks */
1740 DisplaySuspender ds;
1742 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1743 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1744 hide_track_in_display (*i);
1748 vertical_adjustment.set_value (0.0);
1751 redo_visual_stack.push_back (current_visual_state (both_axes));
1756 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1758 start = max_framepos;
1762 //ToDo: if notes are selected, set extents to that selection
1764 //ToDo: if control points are selected, set extents to that selection
1766 if ( !selection->regions.empty() ) {
1767 RegionSelection rs = get_regions_from_selection_and_entered ();
1769 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1771 if ((*i)->region()->position() < start) {
1772 start = (*i)->region()->position();
1775 if ((*i)->region()->last_frame() + 1 > end) {
1776 end = (*i)->region()->last_frame() + 1;
1780 } else if (!selection->time.empty()) {
1781 start = selection->time.start();
1782 end = selection->time.end_frame();
1784 ret = false; //no selection found
1787 if ((start == 0 && end == 0) || end < start) {
1796 Editor::temporal_zoom_selection (bool both_axes)
1798 if (!selection) return;
1800 //ToDo: if notes are selected, zoom to that
1802 //ToDo: if control points are selected, zoom to that
1804 //if region(s) are selected, zoom to that
1805 if ( !selection->regions.empty() )
1806 temporal_zoom_region (both_axes);
1808 //if a range is selected, zoom to that
1809 if (!selection->time.empty()) {
1811 framepos_t start, end;
1812 if (get_selection_extents (start, end)) {
1813 calc_extra_zoom_edges(start, end);
1814 temporal_zoom_by_frame (start, end);
1824 Editor::temporal_zoom_session ()
1826 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1829 framecnt_t start = _session->current_start_frame();
1830 framecnt_t end = _session->current_end_frame();
1832 if (_session->actively_recording () ) {
1833 framepos_t cur = playhead_cursor->current_frame ();
1835 /* recording beyond the end marker; zoom out
1836 * by 5 seconds more so that if 'follow
1837 * playhead' is active we don't immediately
1840 end = cur + _session->frame_rate() * 5;
1844 if ((start == 0 && end == 0) || end < start) {
1848 calc_extra_zoom_edges(start, end);
1850 temporal_zoom_by_frame (start, end);
1855 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1857 if (!_session) return;
1859 if ((start == 0 && end == 0) || end < start) {
1863 framepos_t range = end - start;
1865 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1867 framepos_t new_page = range;
1868 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1869 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1871 if (new_leftmost > middle) {
1875 if (new_leftmost < 0) {
1879 reposition_and_zoom (new_leftmost, new_fpp);
1883 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1889 framecnt_t range_before = frame - leftmost_frame;
1893 if (samples_per_pixel <= 1) {
1896 new_spp = samples_per_pixel + (samples_per_pixel/2);
1898 range_before += range_before/2;
1900 if (samples_per_pixel >= 1) {
1901 new_spp = samples_per_pixel - (samples_per_pixel/2);
1903 /* could bail out here since we cannot zoom any finer,
1904 but leave that to the equality test below
1906 new_spp = samples_per_pixel;
1909 range_before -= range_before/2;
1912 if (new_spp == samples_per_pixel) {
1916 /* zoom focus is automatically taken as @param frame when this
1920 framepos_t new_leftmost = frame - (framepos_t)range_before;
1922 if (new_leftmost > frame) {
1926 if (new_leftmost < 0) {
1930 reposition_and_zoom (new_leftmost, new_spp);
1935 Editor::choose_new_marker_name(string &name) {
1937 if (!ARDOUR_UI::config()->get_name_new_markers()) {
1938 /* don't prompt user for a new name */
1942 ArdourPrompter dialog (true);
1944 dialog.set_prompt (_("New Name:"));
1946 dialog.set_title (_("New Location Marker"));
1948 dialog.set_name ("MarkNameWindow");
1949 dialog.set_size_request (250, -1);
1950 dialog.set_position (Gtk::WIN_POS_MOUSE);
1952 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1953 dialog.set_initial_text (name);
1957 switch (dialog.run ()) {
1958 case RESPONSE_ACCEPT:
1964 dialog.get_result(name);
1971 Editor::add_location_from_selection ()
1975 if (selection->time.empty()) {
1979 if (_session == 0 || clicked_axisview == 0) {
1983 framepos_t start = selection->time[clicked_selection].start;
1984 framepos_t end = selection->time[clicked_selection].end;
1986 _session->locations()->next_available_name(rangename,"selection");
1987 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1989 begin_reversible_command (_("add marker"));
1991 XMLNode &before = _session->locations()->get_state();
1992 _session->locations()->add (location, true);
1993 XMLNode &after = _session->locations()->get_state();
1994 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1996 commit_reversible_command ();
2000 Editor::add_location_mark (framepos_t where)
2004 select_new_marker = true;
2006 _session->locations()->next_available_name(markername,"mark");
2007 if (!choose_new_marker_name(markername)) {
2010 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2011 begin_reversible_command (_("add marker"));
2013 XMLNode &before = _session->locations()->get_state();
2014 _session->locations()->add (location, true);
2015 XMLNode &after = _session->locations()->get_state();
2016 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2018 commit_reversible_command ();
2022 Editor::add_location_from_playhead_cursor ()
2024 add_location_mark (_session->audible_frame());
2028 Editor::remove_location_at_playhead_cursor ()
2033 begin_reversible_command (_("remove marker"));
2035 XMLNode &before = _session->locations()->get_state();
2036 bool removed = false;
2038 //find location(s) at this time
2039 Locations::LocationList locs;
2040 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2041 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2042 if ((*i)->is_mark()) {
2043 _session->locations()->remove (*i);
2050 XMLNode &after = _session->locations()->get_state();
2051 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2053 commit_reversible_command ();
2058 /** Add a range marker around each selected region */
2060 Editor::add_locations_from_region ()
2062 RegionSelection rs = get_regions_from_selection_and_entered ();
2068 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2070 XMLNode &before = _session->locations()->get_state();
2072 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2074 boost::shared_ptr<Region> region = (*i)->region ();
2076 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2078 _session->locations()->add (location, true);
2081 XMLNode &after = _session->locations()->get_state();
2082 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2084 commit_reversible_command ();
2087 /** Add a single range marker around all selected regions */
2089 Editor::add_location_from_region ()
2091 RegionSelection rs = get_regions_from_selection_and_entered ();
2097 begin_reversible_command (_("add marker"));
2099 XMLNode &before = _session->locations()->get_state();
2103 if (rs.size() > 1) {
2104 _session->locations()->next_available_name(markername, "regions");
2106 RegionView* rv = *(rs.begin());
2107 boost::shared_ptr<Region> region = rv->region();
2108 markername = region->name();
2111 if (!choose_new_marker_name(markername)) {
2115 // single range spanning all selected
2116 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2117 _session->locations()->add (location, true);
2119 XMLNode &after = _session->locations()->get_state();
2120 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2122 commit_reversible_command ();
2128 Editor::jump_forward_to_mark ()
2134 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2140 _session->request_locate (pos, _session->transport_rolling());
2144 Editor::jump_backward_to_mark ()
2150 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2156 _session->request_locate (pos, _session->transport_rolling());
2162 framepos_t const pos = _session->audible_frame ();
2165 _session->locations()->next_available_name (markername, "mark");
2167 if (!choose_new_marker_name (markername)) {
2171 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2175 Editor::clear_markers ()
2178 begin_reversible_command (_("clear markers"));
2180 XMLNode &before = _session->locations()->get_state();
2181 _session->locations()->clear_markers ();
2182 XMLNode &after = _session->locations()->get_state();
2183 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2185 commit_reversible_command ();
2190 Editor::clear_ranges ()
2193 begin_reversible_command (_("clear ranges"));
2195 XMLNode &before = _session->locations()->get_state();
2197 _session->locations()->clear_ranges ();
2199 XMLNode &after = _session->locations()->get_state();
2200 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2202 commit_reversible_command ();
2207 Editor::clear_locations ()
2209 begin_reversible_command (_("clear locations"));
2211 XMLNode &before = _session->locations()->get_state();
2212 _session->locations()->clear ();
2213 XMLNode &after = _session->locations()->get_state();
2214 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2216 commit_reversible_command ();
2220 Editor::unhide_markers ()
2222 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2223 Location *l = (*i).first;
2224 if (l->is_hidden() && l->is_mark()) {
2225 l->set_hidden(false, this);
2231 Editor::unhide_ranges ()
2233 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2234 Location *l = (*i).first;
2235 if (l->is_hidden() && l->is_range_marker()) {
2236 l->set_hidden(false, this);
2241 /* INSERT/REPLACE */
2244 Editor::insert_region_list_selection (float times)
2246 RouteTimeAxisView *tv = 0;
2247 boost::shared_ptr<Playlist> playlist;
2249 if (clicked_routeview != 0) {
2250 tv = clicked_routeview;
2251 } else if (!selection->tracks.empty()) {
2252 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2255 } else if (entered_track != 0) {
2256 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2263 if ((playlist = tv->playlist()) == 0) {
2267 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2272 begin_reversible_command (_("insert region"));
2273 playlist->clear_changes ();
2274 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2275 if (Config->get_edit_mode() == Ripple)
2276 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2278 _session->add_command(new StatefulDiffCommand (playlist));
2279 commit_reversible_command ();
2282 /* BUILT-IN EFFECTS */
2285 Editor::reverse_selection ()
2290 /* GAIN ENVELOPE EDITING */
2293 Editor::edit_envelope ()
2300 Editor::transition_to_rolling (bool fwd)
2306 if (_session->config.get_external_sync()) {
2307 switch (Config->get_sync_source()) {
2311 /* transport controlled by the master */
2316 if (_session->is_auditioning()) {
2317 _session->cancel_audition ();
2321 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2325 Editor::play_from_start ()
2327 _session->request_locate (_session->current_start_frame(), true);
2331 Editor::play_from_edit_point ()
2333 _session->request_locate (get_preferred_edit_position(), true);
2337 Editor::play_from_edit_point_and_return ()
2339 framepos_t start_frame;
2340 framepos_t return_frame;
2342 start_frame = get_preferred_edit_position (true);
2344 if (_session->transport_rolling()) {
2345 _session->request_locate (start_frame, false);
2349 /* don't reset the return frame if its already set */
2351 if ((return_frame = _session->requested_return_frame()) < 0) {
2352 return_frame = _session->audible_frame();
2355 if (start_frame >= 0) {
2356 _session->request_roll_at_and_return (start_frame, return_frame);
2361 Editor::play_selection ()
2363 framepos_t start, end;
2364 if (!get_selection_extents ( start, end))
2367 AudioRange ar (start, end, 0);
2368 list<AudioRange> lar;
2371 _session->request_play_range (&lar, true);
2375 Editor::get_preroll ()
2377 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2382 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2384 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2387 location -= get_preroll();
2389 //don't try to locate before the beginning of time
2393 //if follow_playhead is on, keep the playhead on the screen
2394 if ( _follow_playhead )
2395 if ( location < leftmost_frame )
2396 location = leftmost_frame;
2398 _session->request_locate( location );
2402 Editor::play_with_preroll ()
2405 framepos_t preroll = get_preroll();
2407 framepos_t start, end;
2408 if (!get_selection_extents ( start, end))
2411 if (start > preroll)
2412 start = start - preroll;
2414 end = end + preroll; //"post-roll"
2416 AudioRange ar (start, end, 0);
2417 list<AudioRange> lar;
2420 _session->request_play_range (&lar, true);
2425 Editor::play_location (Location& location)
2427 if (location.start() <= location.end()) {
2431 _session->request_bounded_roll (location.start(), location.end());
2435 Editor::loop_location (Location& location)
2437 if (location.start() <= location.end()) {
2443 if ((tll = transport_loop_location()) != 0) {
2444 tll->set (location.start(), location.end());
2446 // enable looping, reposition and start rolling
2447 _session->request_locate (tll->start(), true);
2448 _session->request_play_loop (true);
2453 Editor::do_layer_operation (LayerOperation op)
2455 if (selection->regions.empty ()) {
2459 bool const multiple = selection->regions.size() > 1;
2463 begin_reversible_command (_("raise regions"));
2465 begin_reversible_command (_("raise region"));
2471 begin_reversible_command (_("raise regions to top"));
2473 begin_reversible_command (_("raise region to top"));
2479 begin_reversible_command (_("lower regions"));
2481 begin_reversible_command (_("lower region"));
2487 begin_reversible_command (_("lower regions to bottom"));
2489 begin_reversible_command (_("lower region"));
2494 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2495 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2496 (*i)->clear_owned_changes ();
2499 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2500 boost::shared_ptr<Region> r = (*i)->region ();
2512 r->lower_to_bottom ();
2516 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2517 vector<Command*> cmds;
2519 _session->add_commands (cmds);
2522 commit_reversible_command ();
2526 Editor::raise_region ()
2528 do_layer_operation (Raise);
2532 Editor::raise_region_to_top ()
2534 do_layer_operation (RaiseToTop);
2538 Editor::lower_region ()
2540 do_layer_operation (Lower);
2544 Editor::lower_region_to_bottom ()
2546 do_layer_operation (LowerToBottom);
2549 /** Show the region editor for the selected regions */
2551 Editor::show_region_properties ()
2553 selection->foreach_regionview (&RegionView::show_region_editor);
2556 /** Show the midi list editor for the selected MIDI regions */
2558 Editor::show_midi_list_editor ()
2560 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2564 Editor::rename_region ()
2566 RegionSelection rs = get_regions_from_selection_and_entered ();
2572 ArdourDialog d (*this, _("Rename Region"), true, false);
2574 Label label (_("New name:"));
2577 hbox.set_spacing (6);
2578 hbox.pack_start (label, false, false);
2579 hbox.pack_start (entry, true, true);
2581 d.get_vbox()->set_border_width (12);
2582 d.get_vbox()->pack_start (hbox, false, false);
2584 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2585 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2587 d.set_size_request (300, -1);
2589 entry.set_text (rs.front()->region()->name());
2590 entry.select_region (0, -1);
2592 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2598 int const ret = d.run();
2602 if (ret != RESPONSE_OK) {
2606 std::string str = entry.get_text();
2607 strip_whitespace_edges (str);
2609 rs.front()->region()->set_name (str);
2610 _regions->redisplay ();
2615 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2617 if (_session->is_auditioning()) {
2618 _session->cancel_audition ();
2621 // note: some potential for creativity here, because region doesn't
2622 // have to belong to the playlist that Route is handling
2624 // bool was_soloed = route.soloed();
2626 route.set_solo (true, this);
2628 _session->request_bounded_roll (region->position(), region->position() + region->length());
2630 /* XXX how to unset the solo state ? */
2633 /** Start an audition of the first selected region */
2635 Editor::play_edit_range ()
2637 framepos_t start, end;
2639 if (get_edit_op_range (start, end)) {
2640 _session->request_bounded_roll (start, end);
2645 Editor::play_selected_region ()
2647 framepos_t start = max_framepos;
2650 RegionSelection rs = get_regions_from_selection_and_entered ();
2656 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2657 if ((*i)->region()->position() < start) {
2658 start = (*i)->region()->position();
2660 if ((*i)->region()->last_frame() + 1 > end) {
2661 end = (*i)->region()->last_frame() + 1;
2665 _session->request_bounded_roll (start, end);
2669 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2671 _session->audition_region (region);
2675 Editor::region_from_selection ()
2677 if (clicked_axisview == 0) {
2681 if (selection->time.empty()) {
2685 framepos_t start = selection->time[clicked_selection].start;
2686 framepos_t end = selection->time[clicked_selection].end;
2688 TrackViewList tracks = get_tracks_for_range_action ();
2690 framepos_t selection_cnt = end - start + 1;
2692 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2693 boost::shared_ptr<Region> current;
2694 boost::shared_ptr<Playlist> pl;
2695 framepos_t internal_start;
2698 if ((pl = (*i)->playlist()) == 0) {
2702 if ((current = pl->top_region_at (start)) == 0) {
2706 internal_start = start - current->position();
2707 RegionFactory::region_name (new_name, current->name(), true);
2711 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2712 plist.add (ARDOUR::Properties::length, selection_cnt);
2713 plist.add (ARDOUR::Properties::name, new_name);
2714 plist.add (ARDOUR::Properties::layer, 0);
2716 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2721 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2723 if (selection->time.empty() || selection->tracks.empty()) {
2727 framepos_t start, end;
2728 if (clicked_selection) {
2729 start = selection->time[clicked_selection].start;
2730 end = selection->time[clicked_selection].end;
2732 start = selection->time.start();
2733 end = selection->time.end_frame();
2736 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2737 sort_track_selection (ts);
2739 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2740 boost::shared_ptr<Region> current;
2741 boost::shared_ptr<Playlist> playlist;
2742 framepos_t internal_start;
2745 if ((playlist = (*i)->playlist()) == 0) {
2749 if ((current = playlist->top_region_at(start)) == 0) {
2753 internal_start = start - current->position();
2754 RegionFactory::region_name (new_name, current->name(), true);
2758 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2759 plist.add (ARDOUR::Properties::length, end - start + 1);
2760 plist.add (ARDOUR::Properties::name, new_name);
2762 new_regions.push_back (RegionFactory::create (current, plist));
2767 Editor::split_multichannel_region ()
2769 RegionSelection rs = get_regions_from_selection_and_entered ();
2775 vector< boost::shared_ptr<Region> > v;
2777 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2778 (*x)->region()->separate_by_channel (*_session, v);
2783 Editor::new_region_from_selection ()
2785 region_from_selection ();
2786 cancel_selection ();
2790 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2792 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2793 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2794 case Evoral::OverlapNone:
2802 * - selected tracks, or if there are none...
2803 * - tracks containing selected regions, or if there are none...
2808 Editor::get_tracks_for_range_action () const
2812 if (selection->tracks.empty()) {
2814 /* use tracks with selected regions */
2816 RegionSelection rs = selection->regions;
2818 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2819 TimeAxisView* tv = &(*i)->get_time_axis_view();
2821 if (!t.contains (tv)) {
2827 /* no regions and no tracks: use all tracks */
2833 t = selection->tracks;
2836 return t.filter_to_unique_playlists();
2840 Editor::separate_regions_between (const TimeSelection& ts)
2842 bool in_command = false;
2843 boost::shared_ptr<Playlist> playlist;
2844 RegionSelection new_selection;
2846 TrackViewList tmptracks = get_tracks_for_range_action ();
2847 sort_track_selection (tmptracks);
2849 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2851 RouteTimeAxisView* rtv;
2853 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2855 if (rtv->is_track()) {
2857 /* no edits to destructive tracks */
2859 if (rtv->track()->destructive()) {
2863 if ((playlist = rtv->playlist()) != 0) {
2865 playlist->clear_changes ();
2867 /* XXX need to consider musical time selections here at some point */
2869 double speed = rtv->track()->speed();
2872 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2874 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2875 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2877 latest_regionviews.clear ();
2879 playlist->partition ((framepos_t)((*t).start * speed),
2880 (framepos_t)((*t).end * speed), false);
2884 if (!latest_regionviews.empty()) {
2886 rtv->view()->foreach_regionview (sigc::bind (
2887 sigc::ptr_fun (add_if_covered),
2888 &(*t), &new_selection));
2891 begin_reversible_command (_("separate"));
2895 /* pick up changes to existing regions */
2897 vector<Command*> cmds;
2898 playlist->rdiff (cmds);
2899 _session->add_commands (cmds);
2901 /* pick up changes to the playlist itself (adds/removes)
2904 _session->add_command(new StatefulDiffCommand (playlist));
2913 // selection->set (new_selection);
2915 commit_reversible_command ();
2919 struct PlaylistState {
2920 boost::shared_ptr<Playlist> playlist;
2924 /** Take tracks from get_tracks_for_range_action and cut any regions
2925 * on those tracks so that the tracks are empty over the time
2929 Editor::separate_region_from_selection ()
2931 /* preferentially use *all* ranges in the time selection if we're in range mode
2932 to allow discontiguous operation, since get_edit_op_range() currently
2933 returns a single range.
2936 if (!selection->time.empty()) {
2938 separate_regions_between (selection->time);
2945 if (get_edit_op_range (start, end)) {
2947 AudioRange ar (start, end, 1);
2951 separate_regions_between (ts);
2957 Editor::separate_region_from_punch ()
2959 Location* loc = _session->locations()->auto_punch_location();
2961 separate_regions_using_location (*loc);
2966 Editor::separate_region_from_loop ()
2968 Location* loc = _session->locations()->auto_loop_location();
2970 separate_regions_using_location (*loc);
2975 Editor::separate_regions_using_location (Location& loc)
2977 if (loc.is_mark()) {
2981 AudioRange ar (loc.start(), loc.end(), 1);
2986 separate_regions_between (ts);
2989 /** Separate regions under the selected region */
2991 Editor::separate_under_selected_regions ()
2993 vector<PlaylistState> playlists;
2997 rs = get_regions_from_selection_and_entered();
2999 if (!_session || rs.empty()) {
3003 begin_reversible_command (_("separate region under"));
3005 list<boost::shared_ptr<Region> > regions_to_remove;
3007 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3008 // we can't just remove the region(s) in this loop because
3009 // this removes them from the RegionSelection, and they thus
3010 // disappear from underneath the iterator, and the ++i above
3011 // SEGVs in a puzzling fashion.
3013 // so, first iterate over the regions to be removed from rs and
3014 // add them to the regions_to_remove list, and then
3015 // iterate over the list to actually remove them.
3017 regions_to_remove.push_back ((*i)->region());
3020 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3022 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3025 // is this check necessary?
3029 vector<PlaylistState>::iterator i;
3031 //only take state if this is a new playlist.
3032 for (i = playlists.begin(); i != playlists.end(); ++i) {
3033 if ((*i).playlist == playlist) {
3038 if (i == playlists.end()) {
3040 PlaylistState before;
3041 before.playlist = playlist;
3042 before.before = &playlist->get_state();
3044 playlist->freeze ();
3045 playlists.push_back(before);
3048 //Partition on the region bounds
3049 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3051 //Re-add region that was just removed due to the partition operation
3052 playlist->add_region( (*rl), (*rl)->first_frame() );
3055 vector<PlaylistState>::iterator pl;
3057 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3058 (*pl).playlist->thaw ();
3059 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3062 commit_reversible_command ();
3066 Editor::crop_region_to_selection ()
3068 if (!selection->time.empty()) {
3070 crop_region_to (selection->time.start(), selection->time.end_frame());
3077 if (get_edit_op_range (start, end)) {
3078 crop_region_to (start, end);
3085 Editor::crop_region_to (framepos_t start, framepos_t end)
3087 vector<boost::shared_ptr<Playlist> > playlists;
3088 boost::shared_ptr<Playlist> playlist;
3091 if (selection->tracks.empty()) {
3092 ts = track_views.filter_to_unique_playlists();
3094 ts = selection->tracks.filter_to_unique_playlists ();
3097 sort_track_selection (ts);
3099 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3101 RouteTimeAxisView* rtv;
3103 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3105 boost::shared_ptr<Track> t = rtv->track();
3107 if (t != 0 && ! t->destructive()) {
3109 if ((playlist = rtv->playlist()) != 0) {
3110 playlists.push_back (playlist);
3116 if (playlists.empty()) {
3120 framepos_t the_start;
3124 begin_reversible_command (_("trim to selection"));
3126 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3128 boost::shared_ptr<Region> region;
3132 if ((region = (*i)->top_region_at(the_start)) == 0) {
3136 /* now adjust lengths to that we do the right thing
3137 if the selection extends beyond the region
3140 the_start = max (the_start, (framepos_t) region->position());
3141 if (max_framepos - the_start < region->length()) {
3142 the_end = the_start + region->length() - 1;
3144 the_end = max_framepos;
3146 the_end = min (end, the_end);
3147 cnt = the_end - the_start + 1;
3149 region->clear_changes ();
3150 region->trim_to (the_start, cnt);
3151 _session->add_command (new StatefulDiffCommand (region));
3154 commit_reversible_command ();
3158 Editor::region_fill_track ()
3160 RegionSelection rs = get_regions_from_selection_and_entered ();
3162 if (!_session || rs.empty()) {
3166 framepos_t const end = _session->current_end_frame ();
3168 begin_reversible_command (Operations::region_fill);
3170 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3172 boost::shared_ptr<Region> region ((*i)->region());
3174 boost::shared_ptr<Playlist> pl = region->playlist();
3176 if (end <= region->last_frame()) {
3180 double times = (double) (end - region->last_frame()) / (double) region->length();
3186 pl->clear_changes ();
3187 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3188 _session->add_command (new StatefulDiffCommand (pl));
3191 commit_reversible_command ();
3195 Editor::region_fill_selection ()
3197 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3201 if (selection->time.empty()) {
3205 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3210 framepos_t start = selection->time[clicked_selection].start;
3211 framepos_t end = selection->time[clicked_selection].end;
3213 boost::shared_ptr<Playlist> playlist;
3215 if (selection->tracks.empty()) {
3219 framepos_t selection_length = end - start;
3220 float times = (float)selection_length / region->length();
3222 begin_reversible_command (Operations::fill_selection);
3224 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3226 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3228 if ((playlist = (*i)->playlist()) == 0) {
3232 playlist->clear_changes ();
3233 playlist->add_region (RegionFactory::create (region, true), start, times);
3234 _session->add_command (new StatefulDiffCommand (playlist));
3237 commit_reversible_command ();
3241 Editor::set_region_sync_position ()
3243 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3247 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3249 bool in_command = false;
3251 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3253 if (!(*r)->region()->covers (where)) {
3257 boost::shared_ptr<Region> region ((*r)->region());
3260 begin_reversible_command (_("set sync point"));
3264 region->clear_changes ();
3265 region->set_sync_position (where);
3266 _session->add_command(new StatefulDiffCommand (region));
3270 commit_reversible_command ();
3274 /** Remove the sync positions of the selection */
3276 Editor::remove_region_sync ()
3278 RegionSelection rs = get_regions_from_selection_and_entered ();
3284 begin_reversible_command (_("remove region sync"));
3286 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3288 (*i)->region()->clear_changes ();
3289 (*i)->region()->clear_sync_position ();
3290 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3293 commit_reversible_command ();
3297 Editor::naturalize_region ()
3299 RegionSelection rs = get_regions_from_selection_and_entered ();
3305 if (rs.size() > 1) {
3306 begin_reversible_command (_("move regions to original position"));
3308 begin_reversible_command (_("move region to original position"));
3311 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3312 (*i)->region()->clear_changes ();
3313 (*i)->region()->move_to_natural_position ();
3314 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3317 commit_reversible_command ();
3321 Editor::align_regions (RegionPoint what)
3323 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3329 begin_reversible_command (_("align selection"));
3331 framepos_t const position = get_preferred_edit_position ();
3333 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3334 align_region_internal ((*i)->region(), what, position);
3337 commit_reversible_command ();
3340 struct RegionSortByTime {
3341 bool operator() (const RegionView* a, const RegionView* b) {
3342 return a->region()->position() < b->region()->position();
3347 Editor::align_regions_relative (RegionPoint point)
3349 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3355 framepos_t const position = get_preferred_edit_position ();
3357 framepos_t distance = 0;
3361 list<RegionView*> sorted;
3362 rs.by_position (sorted);
3364 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3369 if (position > r->position()) {
3370 distance = position - r->position();
3372 distance = r->position() - position;
3378 if (position > r->last_frame()) {
3379 distance = position - r->last_frame();
3380 pos = r->position() + distance;
3382 distance = r->last_frame() - position;
3383 pos = r->position() - distance;
3389 pos = r->adjust_to_sync (position);
3390 if (pos > r->position()) {
3391 distance = pos - r->position();
3393 distance = r->position() - pos;
3399 if (pos == r->position()) {
3403 begin_reversible_command (_("align selection (relative)"));
3405 /* move first one specially */
3407 r->clear_changes ();
3408 r->set_position (pos);
3409 _session->add_command(new StatefulDiffCommand (r));
3411 /* move rest by the same amount */
3415 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3417 boost::shared_ptr<Region> region ((*i)->region());
3419 region->clear_changes ();
3422 region->set_position (region->position() + distance);
3424 region->set_position (region->position() - distance);
3427 _session->add_command(new StatefulDiffCommand (region));
3431 commit_reversible_command ();
3435 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3437 begin_reversible_command (_("align region"));
3438 align_region_internal (region, point, position);
3439 commit_reversible_command ();
3443 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3445 region->clear_changes ();
3449 region->set_position (region->adjust_to_sync (position));
3453 if (position > region->length()) {
3454 region->set_position (position - region->length());
3459 region->set_position (position);
3463 _session->add_command(new StatefulDiffCommand (region));
3467 Editor::trim_region_front ()
3473 Editor::trim_region_back ()
3475 trim_region (false);
3479 Editor::trim_region (bool front)
3481 framepos_t where = get_preferred_edit_position();
3482 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3488 begin_reversible_command (front ? _("trim front") : _("trim back"));
3490 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3491 if (!(*i)->region()->locked()) {
3493 (*i)->region()->clear_changes ();
3496 (*i)->region()->trim_front (where);
3497 maybe_locate_with_edit_preroll ( where );
3499 (*i)->region()->trim_end (where);
3500 maybe_locate_with_edit_preroll ( where );
3503 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3507 commit_reversible_command ();
3510 /** Trim the end of the selected regions to the position of the edit cursor */
3512 Editor::trim_region_to_loop ()
3514 Location* loc = _session->locations()->auto_loop_location();
3518 trim_region_to_location (*loc, _("trim to loop"));
3522 Editor::trim_region_to_punch ()
3524 Location* loc = _session->locations()->auto_punch_location();
3528 trim_region_to_location (*loc, _("trim to punch"));
3532 Editor::trim_region_to_location (const Location& loc, const char* str)
3534 RegionSelection rs = get_regions_from_selection_and_entered ();
3536 begin_reversible_command (str);
3538 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3539 RegionView* rv = (*x);
3541 /* require region to span proposed trim */
3542 switch (rv->region()->coverage (loc.start(), loc.end())) {
3543 case Evoral::OverlapInternal:
3549 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3558 if (tav->track() != 0) {
3559 speed = tav->track()->speed();
3562 start = session_frame_to_track_frame (loc.start(), speed);
3563 end = session_frame_to_track_frame (loc.end(), speed);
3565 rv->region()->clear_changes ();
3566 rv->region()->trim_to (start, (end - start));
3567 _session->add_command(new StatefulDiffCommand (rv->region()));
3570 commit_reversible_command ();
3574 Editor::trim_region_to_previous_region_end ()
3576 return trim_to_region(false);
3580 Editor::trim_region_to_next_region_start ()
3582 return trim_to_region(true);
3586 Editor::trim_to_region(bool forward)
3588 RegionSelection rs = get_regions_from_selection_and_entered ();
3590 begin_reversible_command (_("trim to region"));
3592 boost::shared_ptr<Region> next_region;
3594 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3596 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3602 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3610 if (atav->track() != 0) {
3611 speed = atav->track()->speed();
3615 boost::shared_ptr<Region> region = arv->region();
3616 boost::shared_ptr<Playlist> playlist (region->playlist());
3618 region->clear_changes ();
3622 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3628 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3629 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3633 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3639 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3641 arv->region_changed (ARDOUR::bounds_change);
3644 _session->add_command(new StatefulDiffCommand (region));
3647 commit_reversible_command ();
3651 Editor::unfreeze_route ()
3653 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3657 clicked_routeview->track()->unfreeze ();
3661 Editor::_freeze_thread (void* arg)
3663 return static_cast<Editor*>(arg)->freeze_thread ();
3667 Editor::freeze_thread ()
3669 /* create event pool because we may need to talk to the session */
3670 SessionEvent::create_per_thread_pool ("freeze events", 64);
3671 /* create per-thread buffers for process() tree to use */
3672 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3673 current_interthread_info->done = true;
3678 Editor::freeze_route ()
3684 /* stop transport before we start. this is important */
3686 _session->request_transport_speed (0.0);
3688 /* wait for just a little while, because the above call is asynchronous */
3690 Glib::usleep (250000);
3692 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3696 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3698 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3699 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3701 d.set_title (_("Cannot freeze"));
3706 if (clicked_routeview->track()->has_external_redirects()) {
3707 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"
3708 "Freezing will only process the signal as far as the first send/insert/return."),
3709 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3711 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3712 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3713 d.set_title (_("Freeze Limits"));
3715 int response = d.run ();
3718 case Gtk::RESPONSE_CANCEL:
3725 InterThreadInfo itt;
3726 current_interthread_info = &itt;
3728 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3730 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3732 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3734 while (!itt.done && !itt.cancel) {
3735 gtk_main_iteration ();
3738 current_interthread_info = 0;
3742 Editor::bounce_range_selection (bool replace, bool enable_processing)
3744 if (selection->time.empty()) {
3748 TrackSelection views = selection->tracks;
3750 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3752 if (enable_processing) {
3754 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3756 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3758 _("You can't perform this operation because the processing of the signal "
3759 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3760 "You can do this without processing, which is a different operation.")
3762 d.set_title (_("Cannot bounce"));
3769 framepos_t start = selection->time[clicked_selection].start;
3770 framepos_t end = selection->time[clicked_selection].end;
3771 framepos_t cnt = end - start + 1;
3773 begin_reversible_command (_("bounce range"));
3775 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3777 RouteTimeAxisView* rtv;
3779 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3783 boost::shared_ptr<Playlist> playlist;
3785 if ((playlist = rtv->playlist()) == 0) {
3789 InterThreadInfo itt;
3791 playlist->clear_changes ();
3792 playlist->clear_owned_changes ();
3794 boost::shared_ptr<Region> r;
3796 if (enable_processing) {
3797 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3799 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3807 list<AudioRange> ranges;
3808 ranges.push_back (AudioRange (start, start+cnt, 0));
3809 playlist->cut (ranges); // discard result
3810 playlist->add_region (r, start);
3813 vector<Command*> cmds;
3814 playlist->rdiff (cmds);
3815 _session->add_commands (cmds);
3817 _session->add_command (new StatefulDiffCommand (playlist));
3820 commit_reversible_command ();
3823 /** Delete selected regions, automation points or a time range */
3827 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3828 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3829 bool deleted = false;
3830 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3831 deleted = current_mixer_strip->delete_processors ();
3837 /** Cut selected regions, automation points or a time range */
3844 /** Copy selected regions, automation points or a time range */
3852 /** @return true if a Cut, Copy or Clear is possible */
3854 Editor::can_cut_copy () const
3856 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3863 /** Cut, copy or clear selected regions, automation points or a time range.
3864 * @param op Operation (Delete, Cut, Copy or Clear)
3867 Editor::cut_copy (CutCopyOp op)
3869 /* only cancel selection if cut/copy is successful.*/
3875 opname = _("delete");
3884 opname = _("clear");
3888 /* if we're deleting something, and the mouse is still pressed,
3889 the thing we started a drag for will be gone when we release
3890 the mouse button(s). avoid this. see part 2 at the end of
3894 if (op == Delete || op == Cut || op == Clear) {
3895 if (_drags->active ()) {
3900 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3901 cut_buffer->clear ();
3903 if (entered_marker) {
3905 /* cut/delete op while pointing at a marker */
3908 Location* loc = find_location_from_marker (entered_marker, ignored);
3910 if (_session && loc) {
3911 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3918 switch (mouse_mode) {
3921 begin_reversible_command (opname + ' ' + X_("MIDI"));
3923 commit_reversible_command ();
3929 bool did_edit = false;
3931 if (!selection->regions.empty() || !selection->points.empty()) {
3932 begin_reversible_command (opname + ' ' + _("objects"));
3935 if (!selection->regions.empty()) {
3936 cut_copy_regions (op, selection->regions);
3938 if (op == Cut || op == Delete) {
3939 selection->clear_regions ();
3943 if (!selection->points.empty()) {
3944 cut_copy_points (op);
3946 if (op == Cut || op == Delete) {
3947 selection->clear_points ();
3950 } else if (selection->time.empty()) {
3951 framepos_t start, end;
3952 /* no time selection, see if we can get an edit range
3955 if (get_edit_op_range (start, end)) {
3956 selection->set (start, end);
3958 } else if (!selection->time.empty()) {
3959 begin_reversible_command (opname + ' ' + _("range"));
3962 cut_copy_ranges (op);
3964 if (op == Cut || op == Delete) {
3965 selection->clear_time ();
3970 /* reset repeated paste state */
3973 commit_reversible_command ();
3976 if (op == Delete || op == Cut || op == Clear) {
3981 struct AutomationRecord {
3982 AutomationRecord () : state (0) , line(NULL) {}
3983 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3985 XMLNode* state; ///< state before any operation
3986 const AutomationLine* line; ///< line this came from
3987 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3990 /** Cut, copy or clear selected automation points.
3991 * @param op Operation (Cut, Copy or Clear)
3994 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
3996 if (selection->points.empty ()) {
4000 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4001 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4003 /* Keep a record of the AutomationLists that we end up using in this operation */
4004 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4007 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4008 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4009 const AutomationLine& line = (*i)->line();
4010 const boost::shared_ptr<AutomationList> al = line.the_list();
4011 if (lists.find (al) == lists.end ()) {
4012 /* We haven't seen this list yet, so make a record for it. This includes
4013 taking a copy of its current state, in case this is needed for undo later.
4015 lists[al] = AutomationRecord (&al->get_state (), &line);
4019 if (op == Cut || op == Copy) {
4020 /* This operation will involve putting things in the cut buffer, so create an empty
4021 ControlList for each of our source lists to put the cut buffer data in.
4023 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4024 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4027 /* Add all selected points to the relevant copy ControlLists */
4028 framepos_t start = std::numeric_limits<framepos_t>::max();
4029 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4030 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4031 AutomationList::const_iterator j = (*i)->model();
4033 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4035 /* Update earliest MIDI start time in beats */
4036 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4038 /* Update earliest session start time in frames */
4039 start = std::min(start, (*i)->line().session_position(j));
4043 /* Snap start time backwards, so copy/paste is snap aligned. */
4045 if (earliest == Evoral::Beats::max()) {
4046 earliest = Evoral::Beats(); // Weird... don't offset
4048 earliest.round_down_to_beat();
4050 if (start == std::numeric_limits<double>::max()) {
4051 start = 0; // Weird... don't offset
4053 snap_to(start, RoundDownMaybe);
4056 const double line_offset = midi ? earliest.to_double() : start;
4057 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4058 /* Correct this copy list so that it is relative to the earliest
4059 start time, so relative ordering between points is preserved
4060 when copying from several lists and the paste starts at the
4061 earliest copied piece of data. */
4062 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4063 (*j)->when -= line_offset;
4066 /* And add it to the cut buffer */
4067 cut_buffer->add (i->second.copy);
4071 if (op == Delete || op == Cut) {
4072 /* This operation needs to remove things from the main AutomationList, so do that now */
4074 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4075 i->first->freeze ();
4078 /* Remove each selected point from its AutomationList */
4079 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4080 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4081 al->erase ((*i)->model ());
4084 /* Thaw the lists and add undo records for them */
4085 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4086 boost::shared_ptr<AutomationList> al = i->first;
4088 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4093 /** Cut, copy or clear selected automation points.
4094 * @param op Operation (Cut, Copy or Clear)
4097 Editor::cut_copy_midi (CutCopyOp op)
4099 Evoral::Beats earliest = Evoral::Beats::max();
4100 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4101 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4103 if (!mrv->selection().empty()) {
4104 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4106 mrv->cut_copy_clear (op);
4108 /* XXX: not ideal, as there may be more than one track involved in the selection */
4109 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4113 if (!selection->points.empty()) {
4114 cut_copy_points (op, earliest, true);
4115 if (op == Cut || op == Delete) {
4116 selection->clear_points ();
4121 struct lt_playlist {
4122 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4123 return a.playlist < b.playlist;
4127 struct PlaylistMapping {
4129 boost::shared_ptr<Playlist> pl;
4131 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4134 /** Remove `clicked_regionview' */
4136 Editor::remove_clicked_region ()
4138 if (clicked_routeview == 0 || clicked_regionview == 0) {
4142 begin_reversible_command (_("remove region"));
4144 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4146 playlist->clear_changes ();
4147 playlist->clear_owned_changes ();
4148 playlist->remove_region (clicked_regionview->region());
4149 if (Config->get_edit_mode() == Ripple)
4150 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4152 /* We might have removed regions, which alters other regions' layering_index,
4153 so we need to do a recursive diff here.
4155 vector<Command*> cmds;
4156 playlist->rdiff (cmds);
4157 _session->add_commands (cmds);
4159 _session->add_command(new StatefulDiffCommand (playlist));
4160 commit_reversible_command ();
4164 /** Remove the selected regions */
4166 Editor::remove_selected_regions ()
4168 RegionSelection rs = get_regions_from_selection_and_entered ();
4170 if (!_session || rs.empty()) {
4174 begin_reversible_command (_("remove region"));
4176 list<boost::shared_ptr<Region> > regions_to_remove;
4178 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4179 // we can't just remove the region(s) in this loop because
4180 // this removes them from the RegionSelection, and they thus
4181 // disappear from underneath the iterator, and the ++i above
4182 // SEGVs in a puzzling fashion.
4184 // so, first iterate over the regions to be removed from rs and
4185 // add them to the regions_to_remove list, and then
4186 // iterate over the list to actually remove them.
4188 regions_to_remove.push_back ((*i)->region());
4191 vector<boost::shared_ptr<Playlist> > playlists;
4193 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4195 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4198 // is this check necessary?
4202 /* get_regions_from_selection_and_entered() guarantees that
4203 the playlists involved are unique, so there is no need
4207 playlists.push_back (playlist);
4209 playlist->clear_changes ();
4210 playlist->clear_owned_changes ();
4211 playlist->freeze ();
4212 playlist->remove_region (*rl);
4213 if (Config->get_edit_mode() == Ripple)
4214 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4218 vector<boost::shared_ptr<Playlist> >::iterator pl;
4220 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4223 /* We might have removed regions, which alters other regions' layering_index,
4224 so we need to do a recursive diff here.
4226 vector<Command*> cmds;
4227 (*pl)->rdiff (cmds);
4228 _session->add_commands (cmds);
4230 _session->add_command(new StatefulDiffCommand (*pl));
4233 commit_reversible_command ();
4236 /** Cut, copy or clear selected regions.
4237 * @param op Operation (Cut, Copy or Clear)
4240 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4242 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4243 a map when we want ordered access to both elements. i think.
4246 vector<PlaylistMapping> pmap;
4248 framepos_t first_position = max_framepos;
4250 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4251 FreezeList freezelist;
4253 /* get ordering correct before we cut/copy */
4255 rs.sort_by_position_and_track ();
4257 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4259 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4261 if (op == Cut || op == Clear || op == Delete) {
4262 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4265 FreezeList::iterator fl;
4267 // only take state if this is a new playlist.
4268 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4274 if (fl == freezelist.end()) {
4275 pl->clear_changes();
4276 pl->clear_owned_changes ();
4278 freezelist.insert (pl);
4283 TimeAxisView* tv = &(*x)->get_time_axis_view();
4284 vector<PlaylistMapping>::iterator z;
4286 for (z = pmap.begin(); z != pmap.end(); ++z) {
4287 if ((*z).tv == tv) {
4292 if (z == pmap.end()) {
4293 pmap.push_back (PlaylistMapping (tv));
4297 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4299 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4302 /* region not yet associated with a playlist (e.g. unfinished
4309 TimeAxisView& tv = (*x)->get_time_axis_view();
4310 boost::shared_ptr<Playlist> npl;
4311 RegionSelection::iterator tmp;
4318 vector<PlaylistMapping>::iterator z;
4320 for (z = pmap.begin(); z != pmap.end(); ++z) {
4321 if ((*z).tv == &tv) {
4326 assert (z != pmap.end());
4329 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4337 boost::shared_ptr<Region> r = (*x)->region();
4338 boost::shared_ptr<Region> _xx;
4344 pl->remove_region (r);
4345 if (Config->get_edit_mode() == Ripple)
4346 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4350 _xx = RegionFactory::create (r);
4351 npl->add_region (_xx, r->position() - first_position);
4352 pl->remove_region (r);
4353 if (Config->get_edit_mode() == Ripple)
4354 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4358 /* copy region before adding, so we're not putting same object into two different playlists */
4359 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4363 pl->remove_region (r);
4364 if (Config->get_edit_mode() == Ripple)
4365 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4374 list<boost::shared_ptr<Playlist> > foo;
4376 /* the pmap is in the same order as the tracks in which selected regions occured */
4378 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4381 foo.push_back ((*i).pl);
4386 cut_buffer->set (foo);
4390 _last_cut_copy_source_track = 0;
4392 _last_cut_copy_source_track = pmap.front().tv;
4396 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4399 /* We might have removed regions, which alters other regions' layering_index,
4400 so we need to do a recursive diff here.
4402 vector<Command*> cmds;
4403 (*pl)->rdiff (cmds);
4404 _session->add_commands (cmds);
4406 _session->add_command (new StatefulDiffCommand (*pl));
4411 Editor::cut_copy_ranges (CutCopyOp op)
4413 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4415 /* Sort the track selection now, so that it if is used, the playlists
4416 selected by the calls below to cut_copy_clear are in the order that
4417 their tracks appear in the editor. This makes things like paste
4418 of ranges work properly.
4421 sort_track_selection (ts);
4424 if (!entered_track) {
4427 ts.push_back (entered_track);
4430 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4431 (*i)->cut_copy_clear (*selection, op);
4436 Editor::paste (float times, bool from_context)
4438 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4440 paste_internal (get_preferred_edit_position (false, from_context), times);
4444 Editor::mouse_paste ()
4449 if (!mouse_frame (where, ignored)) {
4454 paste_internal (where, 1);
4458 Editor::paste_internal (framepos_t position, float times)
4460 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4462 if (cut_buffer->empty(internal_editing())) {
4466 if (position == max_framepos) {
4467 position = get_preferred_edit_position();
4468 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4471 if (position == last_paste_pos) {
4472 /* repeated paste in the same position */
4475 /* paste in new location, reset repeated paste state */
4477 last_paste_pos = position;
4480 /* get everything in the correct order */
4483 if (!selection->tracks.empty()) {
4484 /* If there is a track selection, paste into exactly those tracks and
4485 only those tracks. This allows the user to be explicit and override
4486 the below "do the reasonable thing" logic. */
4487 ts = selection->tracks.filter_to_unique_playlists ();
4488 sort_track_selection (ts);
4490 /* Figure out which track to base the paste at. */
4491 TimeAxisView* base_track = NULL;
4492 if (_edit_point == Editing::EditAtMouse && entered_track) {
4493 /* With the mouse edit point, paste onto the track under the mouse. */
4494 base_track = entered_track;
4495 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4496 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4497 base_track = &entered_regionview->get_time_axis_view();
4498 } else if (_last_cut_copy_source_track) {
4499 /* Paste to the track that the cut/copy came from (see mantis #333). */
4500 base_track = _last_cut_copy_source_track;
4502 /* This is "impossible" since we've copied... well, do nothing. */
4506 /* Walk up to parent if necessary, so base track is a route. */
4507 while (base_track->get_parent()) {
4508 base_track = base_track->get_parent();
4511 /* Add base track and all tracks below it. The paste logic will select
4512 the appropriate object types from the cut buffer in relative order. */
4513 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4514 if ((*i)->order() >= base_track->order()) {
4519 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4520 sort_track_selection (ts);
4522 /* Add automation children of each track in order, for pasting several lines. */
4523 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4524 /* Add any automation children for pasting several lines */
4525 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4530 typedef RouteTimeAxisView::AutomationTracks ATracks;
4531 const ATracks& atracks = rtv->automation_tracks();
4532 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4533 i = ts.insert(i, a->second.get());
4538 /* We now have a list of trackviews starting at base_track, including
4539 automation children, in the order shown in the editor, e.g. R1,
4540 R1.A1, R1.A2, R2, R2.A1, ... */
4543 begin_reversible_command (Operations::paste);
4545 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4546 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4547 /* Only one line copied, and one automation track selected. Do a
4548 "greedy" paste from one automation type to another. */
4550 PasteContext ctx(paste_count, times, ItemCounts(), true);
4551 ts.front()->paste (position, *cut_buffer, ctx);
4555 /* Paste into tracks */
4557 PasteContext ctx(paste_count, times, ItemCounts(), false);
4558 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4559 (*i)->paste (position, *cut_buffer, ctx);
4563 commit_reversible_command ();
4567 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4569 boost::shared_ptr<Playlist> playlist;
4570 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4571 RegionSelection foo;
4573 framepos_t const start_frame = regions.start ();
4574 framepos_t const end_frame = regions.end_frame ();
4576 begin_reversible_command (Operations::duplicate_region);
4578 selection->clear_regions ();
4580 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4582 boost::shared_ptr<Region> r ((*i)->region());
4584 TimeAxisView& tv = (*i)->get_time_axis_view();
4585 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4586 latest_regionviews.clear ();
4587 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4589 playlist = (*i)->region()->playlist();
4590 playlist->clear_changes ();
4591 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4592 _session->add_command(new StatefulDiffCommand (playlist));
4596 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4600 selection->set (foo);
4603 commit_reversible_command ();
4607 Editor::duplicate_selection (float times)
4609 if (selection->time.empty() || selection->tracks.empty()) {
4613 boost::shared_ptr<Playlist> playlist;
4614 vector<boost::shared_ptr<Region> > new_regions;
4615 vector<boost::shared_ptr<Region> >::iterator ri;
4617 create_region_from_selection (new_regions);
4619 if (new_regions.empty()) {
4623 begin_reversible_command (_("duplicate selection"));
4625 ri = new_regions.begin();
4627 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4629 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4630 if ((playlist = (*i)->playlist()) == 0) {
4633 playlist->clear_changes ();
4635 if (clicked_selection) {
4636 end = selection->time[clicked_selection].end;
4638 end = selection->time.end_frame();
4640 playlist->duplicate (*ri, end, times);
4641 _session->add_command (new StatefulDiffCommand (playlist));
4644 if (ri == new_regions.end()) {
4649 commit_reversible_command ();
4652 /** Reset all selected points to the relevant default value */
4654 Editor::reset_point_selection ()
4656 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4657 ARDOUR::AutomationList::iterator j = (*i)->model ();
4658 (*j)->value = (*i)->line().the_list()->default_value ();
4663 Editor::center_playhead ()
4665 float const page = _visible_canvas_width * samples_per_pixel;
4666 center_screen_internal (playhead_cursor->current_frame (), page);
4670 Editor::center_edit_point ()
4672 float const page = _visible_canvas_width * samples_per_pixel;
4673 center_screen_internal (get_preferred_edit_position(), page);
4676 /** Caller must begin and commit a reversible command */
4678 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4680 playlist->clear_changes ();
4682 _session->add_command (new StatefulDiffCommand (playlist));
4686 Editor::nudge_track (bool use_edit, bool forwards)
4688 boost::shared_ptr<Playlist> playlist;
4689 framepos_t distance;
4690 framepos_t next_distance;
4694 start = get_preferred_edit_position();
4699 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4703 if (selection->tracks.empty()) {
4707 begin_reversible_command (_("nudge track"));
4709 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4711 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4713 if ((playlist = (*i)->playlist()) == 0) {
4717 playlist->clear_changes ();
4718 playlist->clear_owned_changes ();
4720 playlist->nudge_after (start, distance, forwards);
4722 vector<Command*> cmds;
4724 playlist->rdiff (cmds);
4725 _session->add_commands (cmds);
4727 _session->add_command (new StatefulDiffCommand (playlist));
4730 commit_reversible_command ();
4734 Editor::remove_last_capture ()
4736 vector<string> choices;
4743 if (Config->get_verify_remove_last_capture()) {
4744 prompt = _("Do you really want to destroy the last capture?"
4745 "\n(This is destructive and cannot be undone)");
4747 choices.push_back (_("No, do nothing."));
4748 choices.push_back (_("Yes, destroy it."));
4750 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4752 if (prompter.run () == 1) {
4753 _session->remove_last_capture ();
4754 _regions->redisplay ();
4758 _session->remove_last_capture();
4759 _regions->redisplay ();
4764 Editor::normalize_region ()
4770 RegionSelection rs = get_regions_from_selection_and_entered ();
4776 NormalizeDialog dialog (rs.size() > 1);
4778 if (dialog.run () == RESPONSE_CANCEL) {
4782 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4785 /* XXX: should really only count audio regions here */
4786 int const regions = rs.size ();
4788 /* Make a list of the selected audio regions' maximum amplitudes, and also
4789 obtain the maximum amplitude of them all.
4791 list<double> max_amps;
4793 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4794 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4796 dialog.descend (1.0 / regions);
4797 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4800 /* the user cancelled the operation */
4804 max_amps.push_back (a);
4805 max_amp = max (max_amp, a);
4810 begin_reversible_command (_("normalize"));
4812 list<double>::const_iterator a = max_amps.begin ();
4814 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4815 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4820 arv->region()->clear_changes ();
4822 double const amp = dialog.normalize_individually() ? *a : max_amp;
4824 arv->audio_region()->normalize (amp, dialog.target ());
4825 _session->add_command (new StatefulDiffCommand (arv->region()));
4830 commit_reversible_command ();
4835 Editor::reset_region_scale_amplitude ()
4841 RegionSelection rs = get_regions_from_selection_and_entered ();
4847 begin_reversible_command ("reset gain");
4849 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4850 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4853 arv->region()->clear_changes ();
4854 arv->audio_region()->set_scale_amplitude (1.0f);
4855 _session->add_command (new StatefulDiffCommand (arv->region()));
4858 commit_reversible_command ();
4862 Editor::adjust_region_gain (bool up)
4864 RegionSelection rs = get_regions_from_selection_and_entered ();
4866 if (!_session || rs.empty()) {
4870 begin_reversible_command ("adjust region gain");
4872 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4873 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4878 arv->region()->clear_changes ();
4880 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4888 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4889 _session->add_command (new StatefulDiffCommand (arv->region()));
4892 commit_reversible_command ();
4897 Editor::reverse_region ()
4903 Reverse rev (*_session);
4904 apply_filter (rev, _("reverse regions"));
4908 Editor::strip_region_silence ()
4914 RegionSelection rs = get_regions_from_selection_and_entered ();
4920 std::list<RegionView*> audio_only;
4922 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4923 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4925 audio_only.push_back (arv);
4929 StripSilenceDialog d (_session, audio_only);
4930 int const r = d.run ();
4934 if (r == Gtk::RESPONSE_OK) {
4935 ARDOUR::AudioIntervalMap silences;
4936 d.silences (silences);
4937 StripSilence s (*_session, silences, d.fade_length());
4938 apply_filter (s, _("strip silence"), &d);
4943 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4945 Evoral::Sequence<Evoral::Beats>::Notes selected;
4946 mrv.selection_as_notelist (selected, true);
4948 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
4949 v.push_back (selected);
4951 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4952 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4954 return op (mrv.midi_region()->model(), pos_beats, v);
4958 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
4964 begin_reversible_command (op.name ());
4966 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
4967 RegionSelection::const_iterator tmp = r;
4970 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4973 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4976 _session->add_command (cmd);
4983 commit_reversible_command ();
4987 Editor::fork_region ()
4989 RegionSelection rs = get_regions_from_selection_and_entered ();
4995 begin_reversible_command (_("Fork Region(s)"));
4997 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5000 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5001 RegionSelection::iterator tmp = r;
5004 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5008 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5009 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5010 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5012 playlist->clear_changes ();
5013 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5014 _session->add_command(new StatefulDiffCommand (playlist));
5016 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5023 commit_reversible_command ();
5027 Editor::quantize_region ()
5030 quantize_regions(get_regions_from_selection_and_entered ());
5035 Editor::quantize_regions (const RegionSelection& rs)
5037 if (rs.n_midi_regions() == 0) {
5041 QuantizeDialog* qd = new QuantizeDialog (*this);
5044 const int r = qd->run ();
5047 if (r == Gtk::RESPONSE_OK) {
5048 Quantize quant (qd->snap_start(), qd->snap_end(),
5049 qd->start_grid_size(), qd->end_grid_size(),
5050 qd->strength(), qd->swing(), qd->threshold());
5052 apply_midi_note_edit_op (quant, rs);
5057 Editor::legatize_region (bool shrink_only)
5060 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5065 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5067 if (rs.n_midi_regions() == 0) {
5071 Legatize legatize(shrink_only);
5072 apply_midi_note_edit_op (legatize, rs);
5076 Editor::transform_region ()
5079 transform_regions(get_regions_from_selection_and_entered ());
5084 Editor::transform_regions (const RegionSelection& rs)
5086 if (rs.n_midi_regions() == 0) {
5090 TransformDialog* td = new TransformDialog();
5093 const int r = td->run();
5096 if (r == Gtk::RESPONSE_OK) {
5097 Transform transform(td->get());
5098 apply_midi_note_edit_op(transform, rs);
5103 Editor::insert_patch_change (bool from_context)
5105 RegionSelection rs = get_regions_from_selection_and_entered ();
5111 const framepos_t p = get_preferred_edit_position (false, from_context);
5113 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5114 there may be more than one, but the PatchChangeDialog can only offer
5115 one set of patch menus.
5117 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5119 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5120 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5122 if (d.run() == RESPONSE_CANCEL) {
5126 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5127 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5129 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5130 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5137 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5139 RegionSelection rs = get_regions_from_selection_and_entered ();
5145 begin_reversible_command (command);
5147 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5151 int const N = rs.size ();
5153 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5154 RegionSelection::iterator tmp = r;
5157 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5159 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5162 progress->descend (1.0 / N);
5165 if (arv->audio_region()->apply (filter, progress) == 0) {
5167 playlist->clear_changes ();
5168 playlist->clear_owned_changes ();
5170 if (filter.results.empty ()) {
5172 /* no regions returned; remove the old one */
5173 playlist->remove_region (arv->region ());
5177 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5179 /* first region replaces the old one */
5180 playlist->replace_region (arv->region(), *res, (*res)->position());
5184 while (res != filter.results.end()) {
5185 playlist->add_region (*res, (*res)->position());
5191 /* We might have removed regions, which alters other regions' layering_index,
5192 so we need to do a recursive diff here.
5194 vector<Command*> cmds;
5195 playlist->rdiff (cmds);
5196 _session->add_commands (cmds);
5198 _session->add_command(new StatefulDiffCommand (playlist));
5204 progress->ascend ();
5212 commit_reversible_command ();
5216 Editor::external_edit_region ()
5222 Editor::reset_region_gain_envelopes ()
5224 RegionSelection rs = get_regions_from_selection_and_entered ();
5226 if (!_session || rs.empty()) {
5230 begin_reversible_command (_("reset region gain"));
5232 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5233 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5235 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5236 XMLNode& before (alist->get_state());
5238 arv->audio_region()->set_default_envelope ();
5239 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5243 commit_reversible_command ();
5247 Editor::set_region_gain_visibility (RegionView* rv)
5249 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5251 arv->update_envelope_visibility();
5256 Editor::set_gain_envelope_visibility ()
5262 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5263 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5265 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5271 Editor::toggle_gain_envelope_active ()
5273 if (_ignore_region_action) {
5277 RegionSelection rs = get_regions_from_selection_and_entered ();
5279 if (!_session || rs.empty()) {
5283 begin_reversible_command (_("region gain envelope active"));
5285 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5286 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5288 arv->region()->clear_changes ();
5289 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5290 _session->add_command (new StatefulDiffCommand (arv->region()));
5294 commit_reversible_command ();
5298 Editor::toggle_region_lock ()
5300 if (_ignore_region_action) {
5304 RegionSelection rs = get_regions_from_selection_and_entered ();
5306 if (!_session || rs.empty()) {
5310 begin_reversible_command (_("toggle region lock"));
5312 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5313 (*i)->region()->clear_changes ();
5314 (*i)->region()->set_locked (!(*i)->region()->locked());
5315 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5318 commit_reversible_command ();
5322 Editor::toggle_region_video_lock ()
5324 if (_ignore_region_action) {
5328 RegionSelection rs = get_regions_from_selection_and_entered ();
5330 if (!_session || rs.empty()) {
5334 begin_reversible_command (_("Toggle Video Lock"));
5336 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5337 (*i)->region()->clear_changes ();
5338 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5339 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5342 commit_reversible_command ();
5346 Editor::toggle_region_lock_style ()
5348 if (_ignore_region_action) {
5352 RegionSelection rs = get_regions_from_selection_and_entered ();
5354 if (!_session || rs.empty()) {
5358 begin_reversible_command (_("region lock style"));
5360 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5361 (*i)->region()->clear_changes ();
5362 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5363 (*i)->region()->set_position_lock_style (ns);
5364 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5367 commit_reversible_command ();
5371 Editor::toggle_opaque_region ()
5373 if (_ignore_region_action) {
5377 RegionSelection rs = get_regions_from_selection_and_entered ();
5379 if (!_session || rs.empty()) {
5383 begin_reversible_command (_("change region opacity"));
5385 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5386 (*i)->region()->clear_changes ();
5387 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5388 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5391 commit_reversible_command ();
5395 Editor::toggle_record_enable ()
5397 bool new_state = false;
5399 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5400 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5403 if (!rtav->is_track())
5407 new_state = !rtav->track()->record_enabled();
5411 rtav->track()->set_record_enabled (new_state, this);
5416 Editor::toggle_solo ()
5418 bool new_state = false;
5420 boost::shared_ptr<RouteList> rl (new RouteList);
5422 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5423 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5430 new_state = !rtav->route()->soloed ();
5434 rl->push_back (rtav->route());
5437 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5441 Editor::toggle_mute ()
5443 bool new_state = false;
5445 boost::shared_ptr<RouteList> rl (new RouteList);
5447 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5448 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5455 new_state = !rtav->route()->muted();
5459 rl->push_back (rtav->route());
5462 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5466 Editor::toggle_solo_isolate ()
5472 Editor::fade_range ()
5474 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5476 begin_reversible_command (_("fade range"));
5478 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5479 (*i)->fade_range (selection->time);
5482 commit_reversible_command ();
5487 Editor::set_fade_length (bool in)
5489 RegionSelection rs = get_regions_from_selection_and_entered ();
5495 /* we need a region to measure the offset from the start */
5497 RegionView* rv = rs.front ();
5499 framepos_t pos = get_preferred_edit_position();
5503 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5504 /* edit point is outside the relevant region */
5509 if (pos <= rv->region()->position()) {
5513 len = pos - rv->region()->position();
5514 cmd = _("set fade in length");
5516 if (pos >= rv->region()->last_frame()) {
5520 len = rv->region()->last_frame() - pos;
5521 cmd = _("set fade out length");
5524 begin_reversible_command (cmd);
5526 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5527 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5533 boost::shared_ptr<AutomationList> alist;
5535 alist = tmp->audio_region()->fade_in();
5537 alist = tmp->audio_region()->fade_out();
5540 XMLNode &before = alist->get_state();
5543 tmp->audio_region()->set_fade_in_length (len);
5544 tmp->audio_region()->set_fade_in_active (true);
5546 tmp->audio_region()->set_fade_out_length (len);
5547 tmp->audio_region()->set_fade_out_active (true);
5550 XMLNode &after = alist->get_state();
5551 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5554 commit_reversible_command ();
5558 Editor::set_fade_in_shape (FadeShape shape)
5560 RegionSelection rs = get_regions_from_selection_and_entered ();
5566 begin_reversible_command (_("set fade in shape"));
5568 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5569 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5575 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5576 XMLNode &before = alist->get_state();
5578 tmp->audio_region()->set_fade_in_shape (shape);
5580 XMLNode &after = alist->get_state();
5581 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5584 commit_reversible_command ();
5589 Editor::set_fade_out_shape (FadeShape shape)
5591 RegionSelection rs = get_regions_from_selection_and_entered ();
5597 begin_reversible_command (_("set fade out shape"));
5599 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5600 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5606 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5607 XMLNode &before = alist->get_state();
5609 tmp->audio_region()->set_fade_out_shape (shape);
5611 XMLNode &after = alist->get_state();
5612 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5615 commit_reversible_command ();
5619 Editor::set_fade_in_active (bool yn)
5621 RegionSelection rs = get_regions_from_selection_and_entered ();
5627 begin_reversible_command (_("set fade in active"));
5629 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5630 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5637 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5639 ar->clear_changes ();
5640 ar->set_fade_in_active (yn);
5641 _session->add_command (new StatefulDiffCommand (ar));
5644 commit_reversible_command ();
5648 Editor::set_fade_out_active (bool yn)
5650 RegionSelection rs = get_regions_from_selection_and_entered ();
5656 begin_reversible_command (_("set fade out active"));
5658 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5659 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5665 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5667 ar->clear_changes ();
5668 ar->set_fade_out_active (yn);
5669 _session->add_command(new StatefulDiffCommand (ar));
5672 commit_reversible_command ();
5676 Editor::toggle_region_fades (int dir)
5678 if (_ignore_region_action) {
5682 boost::shared_ptr<AudioRegion> ar;
5685 RegionSelection rs = get_regions_from_selection_and_entered ();
5691 RegionSelection::iterator i;
5692 for (i = rs.begin(); i != rs.end(); ++i) {
5693 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5695 yn = ar->fade_out_active ();
5697 yn = ar->fade_in_active ();
5703 if (i == rs.end()) {
5707 /* XXX should this undo-able? */
5709 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5710 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5713 if (dir == 1 || dir == 0) {
5714 ar->set_fade_in_active (!yn);
5717 if (dir == -1 || dir == 0) {
5718 ar->set_fade_out_active (!yn);
5724 /** Update region fade visibility after its configuration has been changed */
5726 Editor::update_region_fade_visibility ()
5728 bool _fade_visibility = _session->config.get_show_region_fades ();
5730 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5731 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5733 if (_fade_visibility) {
5734 v->audio_view()->show_all_fades ();
5736 v->audio_view()->hide_all_fades ();
5743 Editor::set_edit_point ()
5748 if (!mouse_frame (where, ignored)) {
5754 if (selection->markers.empty()) {
5756 mouse_add_new_marker (where);
5761 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5764 loc->move_to (where);
5770 Editor::set_playhead_cursor ()
5772 if (entered_marker) {
5773 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5778 if (!mouse_frame (where, ignored)) {
5785 _session->request_locate (where, _session->transport_rolling());
5789 if (ARDOUR_UI::config()->get_follow_edits()) {
5790 cancel_time_selection();
5795 Editor::split_region ()
5797 //if a range is selected, separate it
5798 if ( !selection->time.empty()) {
5799 separate_regions_between (selection->time);
5803 //if no range was selected, try to find some regions to split
5804 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
5806 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5808 framepos_t where = get_preferred_edit_position ();
5814 split_regions_at (where, rs);
5818 struct EditorOrderRouteSorter {
5819 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5820 return a->order_key () < b->order_key ();
5825 Editor::select_next_route()
5827 if (selection->tracks.empty()) {
5828 selection->set (track_views.front());
5832 TimeAxisView* current = selection->tracks.front();
5836 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5837 if (*i == current) {
5839 if (i != track_views.end()) {
5842 current = (*(track_views.begin()));
5843 //selection->set (*(track_views.begin()));
5848 rui = dynamic_cast<RouteUI *>(current);
5849 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5851 selection->set(current);
5853 ensure_time_axis_view_is_visible (*current, false);
5857 Editor::select_prev_route()
5859 if (selection->tracks.empty()) {
5860 selection->set (track_views.front());
5864 TimeAxisView* current = selection->tracks.front();
5868 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5869 if (*i == current) {
5871 if (i != track_views.rend()) {
5874 current = *(track_views.rbegin());
5879 rui = dynamic_cast<RouteUI *>(current);
5880 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5882 selection->set (current);
5884 ensure_time_axis_view_is_visible (*current, false);
5888 Editor::set_loop_from_selection (bool play)
5890 if (_session == 0) {
5894 framepos_t start, end;
5895 if (!get_selection_extents ( start, end))
5898 set_loop_range (start, end, _("set loop range from selection"));
5901 _session->request_play_loop (true, true);
5906 Editor::set_loop_from_region (bool play)
5908 framepos_t start, end;
5909 if (!get_selection_extents ( start, end))
5912 set_loop_range (start, end, _("set loop range from region"));
5915 _session->request_locate (start, true);
5916 _session->request_play_loop (true);
5921 Editor::set_punch_from_selection ()
5923 if (_session == 0) {
5927 framepos_t start, end;
5928 if (!get_selection_extents ( start, end))
5931 set_punch_range (start, end, _("set punch range from selection"));
5935 Editor::set_session_extents_from_selection ()
5937 if (_session == 0) {
5941 framepos_t start, end;
5942 if (!get_selection_extents ( start, end))
5945 begin_reversible_command (_("set session start/stop from selection"));
5948 if ((loc = _session->locations()->session_range_location()) == 0) {
5949 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5951 XMLNode &before = loc->get_state();
5953 _session->set_session_extents ( start, end );
5955 XMLNode &after = loc->get_state();
5957 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5959 commit_reversible_command ();
5964 Editor::set_punch_from_region ()
5966 framepos_t start, end;
5967 if (!get_selection_extents ( start, end))
5970 set_punch_range (start, end, _("set punch range from region"));
5974 Editor::pitch_shift_region ()
5976 RegionSelection rs = get_regions_from_selection_and_entered ();
5978 RegionSelection audio_rs;
5979 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5980 if (dynamic_cast<AudioRegionView*> (*i)) {
5981 audio_rs.push_back (*i);
5985 if (audio_rs.empty()) {
5989 pitch_shift (audio_rs, 1.2);
5993 Editor::transpose_region ()
5995 RegionSelection rs = get_regions_from_selection_and_entered ();
5997 list<MidiRegionView*> midi_region_views;
5998 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5999 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6001 midi_region_views.push_back (mrv);
6006 int const r = d.run ();
6007 if (r != RESPONSE_ACCEPT) {
6011 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6012 (*i)->midi_region()->transpose (d.semitones ());
6017 Editor::set_tempo_from_region ()
6019 RegionSelection rs = get_regions_from_selection_and_entered ();
6021 if (!_session || rs.empty()) {
6025 RegionView* rv = rs.front();
6027 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6031 Editor::use_range_as_bar ()
6033 framepos_t start, end;
6034 if (get_edit_op_range (start, end)) {
6035 define_one_bar (start, end);
6040 Editor::define_one_bar (framepos_t start, framepos_t end)
6042 framepos_t length = end - start;
6044 const Meter& m (_session->tempo_map().meter_at (start));
6046 /* length = 1 bar */
6048 /* now we want frames per beat.
6049 we have frames per bar, and beats per bar, so ...
6052 /* XXXX METER MATH */
6054 double frames_per_beat = length / m.divisions_per_bar();
6056 /* beats per minute = */
6058 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6060 /* now decide whether to:
6062 (a) set global tempo
6063 (b) add a new tempo marker
6067 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6069 bool do_global = false;
6071 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6073 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6074 at the start, or create a new marker
6077 vector<string> options;
6078 options.push_back (_("Cancel"));
6079 options.push_back (_("Add new marker"));
6080 options.push_back (_("Set global tempo"));
6083 _("Define one bar"),
6084 _("Do you want to set the global tempo or add a new tempo marker?"),
6088 c.set_default_response (2);
6104 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6105 if the marker is at the region starter, change it, otherwise add
6110 begin_reversible_command (_("set tempo from region"));
6111 XMLNode& before (_session->tempo_map().get_state());
6114 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6115 } else if (t.frame() == start) {
6116 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6118 Timecode::BBT_Time bbt;
6119 _session->tempo_map().bbt_time (start, bbt);
6120 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6123 XMLNode& after (_session->tempo_map().get_state());
6125 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6126 commit_reversible_command ();
6130 Editor::split_region_at_transients ()
6132 AnalysisFeatureList positions;
6134 RegionSelection rs = get_regions_from_selection_and_entered ();
6136 if (!_session || rs.empty()) {
6140 begin_reversible_command (_("split regions"));
6142 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6144 RegionSelection::iterator tmp;
6149 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6151 if (ar && (ar->get_transients (positions) == 0)) {
6152 split_region_at_points ((*i)->region(), positions, true);
6159 commit_reversible_command ();
6164 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6166 bool use_rhythmic_rodent = false;
6168 boost::shared_ptr<Playlist> pl = r->playlist();
6170 list<boost::shared_ptr<Region> > new_regions;
6176 if (positions.empty()) {
6181 if (positions.size() > 20 && can_ferret) {
6182 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);
6183 MessageDialog msg (msgstr,
6186 Gtk::BUTTONS_OK_CANCEL);
6189 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6190 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6192 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6195 msg.set_title (_("Excessive split?"));
6198 int response = msg.run();
6204 case RESPONSE_APPLY:
6205 use_rhythmic_rodent = true;
6212 if (use_rhythmic_rodent) {
6213 show_rhythm_ferret ();
6217 AnalysisFeatureList::const_iterator x;
6219 pl->clear_changes ();
6220 pl->clear_owned_changes ();
6222 x = positions.begin();
6224 if (x == positions.end()) {
6229 pl->remove_region (r);
6233 while (x != positions.end()) {
6235 /* deal with positons that are out of scope of present region bounds */
6236 if (*x <= 0 || *x > r->length()) {
6241 /* file start = original start + how far we from the initial position ?
6244 framepos_t file_start = r->start() + pos;
6246 /* length = next position - current position
6249 framepos_t len = (*x) - pos;
6251 /* XXX we do we really want to allow even single-sample regions?
6252 shouldn't we have some kind of lower limit on region size?
6261 if (RegionFactory::region_name (new_name, r->name())) {
6265 /* do NOT announce new regions 1 by one, just wait till they are all done */
6269 plist.add (ARDOUR::Properties::start, file_start);
6270 plist.add (ARDOUR::Properties::length, len);
6271 plist.add (ARDOUR::Properties::name, new_name);
6272 plist.add (ARDOUR::Properties::layer, 0);
6274 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6275 /* because we set annouce to false, manually add the new region to the
6278 RegionFactory::map_add (nr);
6280 pl->add_region (nr, r->position() + pos);
6283 new_regions.push_front(nr);
6292 RegionFactory::region_name (new_name, r->name());
6294 /* Add the final region */
6297 plist.add (ARDOUR::Properties::start, r->start() + pos);
6298 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6299 plist.add (ARDOUR::Properties::name, new_name);
6300 plist.add (ARDOUR::Properties::layer, 0);
6302 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6303 /* because we set annouce to false, manually add the new region to the
6306 RegionFactory::map_add (nr);
6307 pl->add_region (nr, r->position() + pos);
6310 new_regions.push_front(nr);
6315 /* We might have removed regions, which alters other regions' layering_index,
6316 so we need to do a recursive diff here.
6318 vector<Command*> cmds;
6320 _session->add_commands (cmds);
6322 _session->add_command (new StatefulDiffCommand (pl));
6326 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6327 set_selected_regionview_from_region_list ((*i), Selection::Add);
6333 Editor::place_transient()
6339 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6345 framepos_t where = get_preferred_edit_position();
6347 begin_reversible_command (_("place transient"));
6349 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6350 framepos_t position = (*r)->region()->position();
6351 (*r)->region()->add_transient(where - position);
6354 commit_reversible_command ();
6358 Editor::remove_transient(ArdourCanvas::Item* item)
6364 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6367 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6368 _arv->remove_transient (*(float*) _line->get_data ("position"));
6372 Editor::snap_regions_to_grid ()
6374 list <boost::shared_ptr<Playlist > > used_playlists;
6376 RegionSelection rs = get_regions_from_selection_and_entered ();
6378 if (!_session || rs.empty()) {
6382 begin_reversible_command (_("snap regions to grid"));
6384 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6386 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6388 if (!pl->frozen()) {
6389 /* we haven't seen this playlist before */
6391 /* remember used playlists so we can thaw them later */
6392 used_playlists.push_back(pl);
6396 framepos_t start_frame = (*r)->region()->first_frame ();
6397 snap_to (start_frame);
6398 (*r)->region()->set_position (start_frame);
6401 while (used_playlists.size() > 0) {
6402 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6404 used_playlists.pop_front();
6407 commit_reversible_command ();
6411 Editor::close_region_gaps ()
6413 list <boost::shared_ptr<Playlist > > used_playlists;
6415 RegionSelection rs = get_regions_from_selection_and_entered ();
6417 if (!_session || rs.empty()) {
6421 Dialog dialog (_("Close Region Gaps"));
6424 table.set_spacings (12);
6425 table.set_border_width (12);
6426 Label* l = manage (left_aligned_label (_("Crossfade length")));
6427 table.attach (*l, 0, 1, 0, 1);
6429 SpinButton spin_crossfade (1, 0);
6430 spin_crossfade.set_range (0, 15);
6431 spin_crossfade.set_increments (1, 1);
6432 spin_crossfade.set_value (5);
6433 table.attach (spin_crossfade, 1, 2, 0, 1);
6435 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6437 l = manage (left_aligned_label (_("Pull-back length")));
6438 table.attach (*l, 0, 1, 1, 2);
6440 SpinButton spin_pullback (1, 0);
6441 spin_pullback.set_range (0, 100);
6442 spin_pullback.set_increments (1, 1);
6443 spin_pullback.set_value(30);
6444 table.attach (spin_pullback, 1, 2, 1, 2);
6446 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6448 dialog.get_vbox()->pack_start (table);
6449 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6450 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6453 if (dialog.run () == RESPONSE_CANCEL) {
6457 framepos_t crossfade_len = spin_crossfade.get_value();
6458 framepos_t pull_back_frames = spin_pullback.get_value();
6460 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6461 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6463 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6465 begin_reversible_command (_("close region gaps"));
6468 boost::shared_ptr<Region> last_region;
6470 rs.sort_by_position_and_track();
6472 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6474 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6476 if (!pl->frozen()) {
6477 /* we haven't seen this playlist before */
6479 /* remember used playlists so we can thaw them later */
6480 used_playlists.push_back(pl);
6484 framepos_t position = (*r)->region()->position();
6486 if (idx == 0 || position < last_region->position()){
6487 last_region = (*r)->region();
6492 (*r)->region()->trim_front( (position - pull_back_frames));
6493 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6495 last_region = (*r)->region();
6500 while (used_playlists.size() > 0) {
6501 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6503 used_playlists.pop_front();
6506 commit_reversible_command ();
6510 Editor::tab_to_transient (bool forward)
6512 AnalysisFeatureList positions;
6514 RegionSelection rs = get_regions_from_selection_and_entered ();
6520 framepos_t pos = _session->audible_frame ();
6522 if (!selection->tracks.empty()) {
6524 /* don't waste time searching for transients in duplicate playlists.
6527 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6529 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6531 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6534 boost::shared_ptr<Track> tr = rtv->track();
6536 boost::shared_ptr<Playlist> pl = tr->playlist ();
6538 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6541 positions.push_back (result);
6554 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6555 (*r)->region()->get_transients (positions);
6559 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6562 AnalysisFeatureList::iterator x;
6564 for (x = positions.begin(); x != positions.end(); ++x) {
6570 if (x != positions.end ()) {
6571 _session->request_locate (*x);
6575 AnalysisFeatureList::reverse_iterator x;
6577 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6583 if (x != positions.rend ()) {
6584 _session->request_locate (*x);
6590 Editor::playhead_forward_to_grid ()
6596 framepos_t pos = playhead_cursor->current_frame ();
6597 if (pos < max_framepos - 1) {
6599 snap_to_internal (pos, RoundUpAlways, false);
6600 _session->request_locate (pos);
6606 Editor::playhead_backward_to_grid ()
6612 framepos_t pos = playhead_cursor->current_frame ();
6615 snap_to_internal (pos, RoundDownAlways, false);
6616 _session->request_locate (pos);
6621 Editor::set_track_height (Height h)
6623 TrackSelection& ts (selection->tracks);
6625 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6626 (*x)->set_height_enum (h);
6631 Editor::toggle_tracks_active ()
6633 TrackSelection& ts (selection->tracks);
6635 bool target = false;
6641 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6642 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6646 target = !rtv->_route->active();
6649 rtv->_route->set_active (target, this);
6655 Editor::remove_tracks ()
6657 TrackSelection& ts (selection->tracks);
6663 vector<string> choices;
6667 const char* trackstr;
6669 vector<boost::shared_ptr<Route> > routes;
6670 bool special_bus = false;
6672 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6673 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6677 if (rtv->is_track()) {
6682 routes.push_back (rtv->_route);
6684 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6689 if (special_bus && !Config->get_allow_special_bus_removal()) {
6690 MessageDialog msg (_("That would be bad news ...."),
6694 msg.set_secondary_text (string_compose (_(
6695 "Removing the master or monitor bus is such a bad idea\n\
6696 that %1 is not going to allow it.\n\
6698 If you really want to do this sort of thing\n\
6699 edit your ardour.rc file to set the\n\
6700 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6707 if (ntracks + nbusses == 0) {
6711 // XXX should be using gettext plural forms, maybe?
6713 trackstr = _("tracks");
6715 trackstr = _("track");
6719 busstr = _("busses");
6726 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6727 "(You may also lose the playlists associated with the %2)\n\n"
6728 "This action cannot be undone, and the session file will be overwritten!"),
6729 ntracks, trackstr, nbusses, busstr);
6731 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6732 "(You may also lose the playlists associated with the %2)\n\n"
6733 "This action cannot be undone, and the session file will be overwritten!"),
6736 } else if (nbusses) {
6737 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6738 "This action cannot be undone, and the session file will be overwritten"),
6742 choices.push_back (_("No, do nothing."));
6743 if (ntracks + nbusses > 1) {
6744 choices.push_back (_("Yes, remove them."));
6746 choices.push_back (_("Yes, remove it."));
6751 title = string_compose (_("Remove %1"), trackstr);
6753 title = string_compose (_("Remove %1"), busstr);
6756 Choice prompter (title, prompt, choices);
6758 if (prompter.run () != 1) {
6763 Session::StateProtector sp (_session);
6764 DisplaySuspender ds;
6765 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6766 _session->remove_route (*x);
6772 Editor::do_insert_time ()
6774 if (selection->tracks.empty()) {
6778 InsertTimeDialog d (*this);
6779 int response = d.run ();
6781 if (response != RESPONSE_OK) {
6785 if (d.distance() == 0) {
6789 InsertTimeOption opt = d.intersected_region_action ();
6792 get_preferred_edit_position(),
6798 d.move_glued_markers(),
6799 d.move_locked_markers(),
6805 Editor::insert_time (
6806 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6807 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6810 bool commit = false;
6812 if (Config->get_edit_mode() == Lock) {
6816 begin_reversible_command (_("insert time"));
6818 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6820 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6824 /* don't operate on any playlist more than once, which could
6825 * happen if "all playlists" is enabled, but there is more
6826 * than 1 track using playlists "from" a given track.
6829 set<boost::shared_ptr<Playlist> > pl;
6831 if (all_playlists) {
6832 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6834 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6835 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6840 if ((*x)->playlist ()) {
6841 pl.insert ((*x)->playlist ());
6845 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6847 (*i)->clear_changes ();
6848 (*i)->clear_owned_changes ();
6850 if (opt == SplitIntersected) {
6854 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6856 vector<Command*> cmds;
6858 _session->add_commands (cmds);
6860 _session->add_command (new StatefulDiffCommand (*i));
6865 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6867 rtav->route ()->shift (pos, frames);
6875 XMLNode& before (_session->locations()->get_state());
6876 Locations::LocationList copy (_session->locations()->list());
6878 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6880 Locations::LocationList::const_iterator tmp;
6882 bool const was_locked = (*i)->locked ();
6883 if (locked_markers_too) {
6887 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6889 if ((*i)->start() >= pos) {
6890 (*i)->set_start ((*i)->start() + frames);
6891 if (!(*i)->is_mark()) {
6892 (*i)->set_end ((*i)->end() + frames);
6905 XMLNode& after (_session->locations()->get_state());
6906 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6911 _session->tempo_map().insert_time (pos, frames);
6915 commit_reversible_command ();
6920 Editor::fit_selection ()
6922 if (!selection->tracks.empty()) {
6923 fit_tracks (selection->tracks);
6927 /* no selected tracks - use tracks with selected regions */
6929 if (!selection->regions.empty()) {
6930 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6931 tvl.push_back (&(*r)->get_time_axis_view ());
6937 } else if (internal_editing()) {
6938 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6941 if (entered_track) {
6942 tvl.push_back (entered_track);
6951 Editor::fit_tracks (TrackViewList & tracks)
6953 if (tracks.empty()) {
6957 uint32_t child_heights = 0;
6958 int visible_tracks = 0;
6960 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6962 if (!(*t)->marked_for_display()) {
6966 child_heights += (*t)->effective_height() - (*t)->current_height();
6970 /* compute the per-track height from:
6972 total canvas visible height -
6973 height that will be taken by visible children of selected
6974 tracks - height of the ruler/hscroll area
6976 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6977 double first_y_pos = DBL_MAX;
6979 if (h < TimeAxisView::preset_height (HeightSmall)) {
6980 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6981 /* too small to be displayed */
6985 undo_visual_stack.push_back (current_visual_state (true));
6986 no_save_visual = true;
6988 /* build a list of all tracks, including children */
6991 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6993 TimeAxisView::Children c = (*i)->get_child_list ();
6994 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6995 all.push_back (j->get());
6999 bool prev_was_selected = false;
7000 bool is_selected = tracks.contains (all.front());
7001 bool next_is_selected;
7003 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7005 TrackViewList::iterator next;
7010 if (next != all.end()) {
7011 next_is_selected = tracks.contains (*next);
7013 next_is_selected = false;
7016 if ((*t)->marked_for_display ()) {
7018 (*t)->set_height (h);
7019 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7021 if (prev_was_selected && next_is_selected) {
7022 hide_track_in_display (*t);
7027 prev_was_selected = is_selected;
7028 is_selected = next_is_selected;
7032 set the controls_layout height now, because waiting for its size
7033 request signal handler will cause the vertical adjustment setting to fail
7036 controls_layout.property_height () = _full_canvas_height;
7037 vertical_adjustment.set_value (first_y_pos);
7039 redo_visual_stack.push_back (current_visual_state (true));
7041 visible_tracks_selector.set_text (_("Sel"));
7045 Editor::save_visual_state (uint32_t n)
7047 while (visual_states.size() <= n) {
7048 visual_states.push_back (0);
7051 if (visual_states[n] != 0) {
7052 delete visual_states[n];
7055 visual_states[n] = current_visual_state (true);
7060 Editor::goto_visual_state (uint32_t n)
7062 if (visual_states.size() <= n) {
7066 if (visual_states[n] == 0) {
7070 use_visual_state (*visual_states[n]);
7074 Editor::start_visual_state_op (uint32_t n)
7076 save_visual_state (n);
7078 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7080 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7081 pup->set_text (buf);
7086 Editor::cancel_visual_state_op (uint32_t n)
7088 goto_visual_state (n);
7092 Editor::toggle_region_mute ()
7094 if (_ignore_region_action) {
7098 RegionSelection rs = get_regions_from_selection_and_entered ();
7104 if (rs.size() > 1) {
7105 begin_reversible_command (_("mute regions"));
7107 begin_reversible_command (_("mute region"));
7110 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7112 (*i)->region()->playlist()->clear_changes ();
7113 (*i)->region()->set_muted (!(*i)->region()->muted ());
7114 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7118 commit_reversible_command ();
7122 Editor::combine_regions ()
7124 /* foreach track with selected regions, take all selected regions
7125 and join them into a new region containing the subregions (as a
7129 typedef set<RouteTimeAxisView*> RTVS;
7132 if (selection->regions.empty()) {
7136 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7137 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7140 tracks.insert (rtv);
7144 begin_reversible_command (_("combine regions"));
7146 vector<RegionView*> new_selection;
7148 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7151 if ((rv = (*i)->combine_regions ()) != 0) {
7152 new_selection.push_back (rv);
7156 selection->clear_regions ();
7157 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7158 selection->add (*i);
7161 commit_reversible_command ();
7165 Editor::uncombine_regions ()
7167 typedef set<RouteTimeAxisView*> RTVS;
7170 if (selection->regions.empty()) {
7174 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7175 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7178 tracks.insert (rtv);
7182 begin_reversible_command (_("uncombine regions"));
7184 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7185 (*i)->uncombine_regions ();
7188 commit_reversible_command ();
7192 Editor::toggle_midi_input_active (bool flip_others)
7195 boost::shared_ptr<RouteList> rl (new RouteList);
7197 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7198 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7204 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7207 rl->push_back (rtav->route());
7208 onoff = !mt->input_active();
7212 _session->set_exclusive_input_active (rl, onoff, flip_others);
7219 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7221 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7222 lock_dialog->get_vbox()->pack_start (*padlock);
7224 ArdourButton* b = manage (new ArdourButton);
7225 b->set_name ("lock button");
7226 b->set_text (_("Click to unlock"));
7227 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7228 lock_dialog->get_vbox()->pack_start (*b);
7230 lock_dialog->get_vbox()->show_all ();
7231 lock_dialog->set_size_request (200, 200);
7235 /* The global menu bar continues to be accessible to applications
7236 with modal dialogs, which means that we need to desensitize
7237 all items in the menu bar. Since those items are really just
7238 proxies for actions, that means disabling all actions.
7240 ActionManager::disable_all_actions ();
7242 lock_dialog->present ();
7248 lock_dialog->hide ();
7251 ActionManager::pop_action_state ();
7254 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7255 start_lock_event_timing ();
7260 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7262 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7266 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7268 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7269 Gtkmm2ext::UI::instance()->flush_pending ();
7273 Editor::bring_all_sources_into_session ()
7280 ArdourDialog w (_("Moving embedded files into session folder"));
7281 w.get_vbox()->pack_start (msg);
7284 /* flush all pending GUI events because we're about to start copying
7288 Gtkmm2ext::UI::instance()->flush_pending ();
7292 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));