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);
1818 fit_selected_tracks();
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 ( !selection->time.empty()) {
5798 separate_regions_between (selection->time);
5802 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5804 framepos_t where = get_preferred_edit_position ();
5810 split_regions_at (where, rs);
5813 struct EditorOrderRouteSorter {
5814 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5815 return a->order_key () < b->order_key ();
5820 Editor::select_next_route()
5822 if (selection->tracks.empty()) {
5823 selection->set (track_views.front());
5827 TimeAxisView* current = selection->tracks.front();
5831 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5832 if (*i == current) {
5834 if (i != track_views.end()) {
5837 current = (*(track_views.begin()));
5838 //selection->set (*(track_views.begin()));
5843 rui = dynamic_cast<RouteUI *>(current);
5844 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5846 selection->set(current);
5848 ensure_time_axis_view_is_visible (*current, false);
5852 Editor::select_prev_route()
5854 if (selection->tracks.empty()) {
5855 selection->set (track_views.front());
5859 TimeAxisView* current = selection->tracks.front();
5863 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5864 if (*i == current) {
5866 if (i != track_views.rend()) {
5869 current = *(track_views.rbegin());
5874 rui = dynamic_cast<RouteUI *>(current);
5875 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5877 selection->set (current);
5879 ensure_time_axis_view_is_visible (*current, false);
5883 Editor::set_loop_from_selection (bool play)
5885 if (_session == 0) {
5889 framepos_t start, end;
5890 if (!get_selection_extents ( start, end))
5893 set_loop_range (start, end, _("set loop range from selection"));
5896 _session->request_locate (start, true);
5897 _session->request_play_loop (true);
5902 Editor::set_loop_from_region (bool play)
5904 framepos_t start, end;
5905 if (!get_selection_extents ( start, end))
5908 set_loop_range (start, end, _("set loop range from region"));
5911 _session->request_locate (start, true);
5912 _session->request_play_loop (true);
5917 Editor::set_punch_from_selection ()
5919 if (_session == 0) {
5923 framepos_t start, end;
5924 if (!get_selection_extents ( start, end))
5927 set_punch_range (start, end, _("set punch range from selection"));
5931 Editor::set_session_extents_from_selection ()
5933 if (_session == 0) {
5937 framepos_t start, end;
5938 if (!get_selection_extents ( start, end))
5941 begin_reversible_command (_("set session start/stop from selection"));
5944 if ((loc = _session->locations()->session_range_location()) == 0) {
5945 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5947 XMLNode &before = loc->get_state();
5949 _session->set_session_extents ( start, end );
5951 XMLNode &after = loc->get_state();
5953 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5955 commit_reversible_command ();
5960 Editor::set_punch_from_region ()
5962 framepos_t start, end;
5963 if (!get_selection_extents ( start, end))
5966 set_punch_range (start, end, _("set punch range from region"));
5970 Editor::pitch_shift_region ()
5972 RegionSelection rs = get_regions_from_selection_and_entered ();
5974 RegionSelection audio_rs;
5975 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5976 if (dynamic_cast<AudioRegionView*> (*i)) {
5977 audio_rs.push_back (*i);
5981 if (audio_rs.empty()) {
5985 pitch_shift (audio_rs, 1.2);
5989 Editor::transpose_region ()
5991 RegionSelection rs = get_regions_from_selection_and_entered ();
5993 list<MidiRegionView*> midi_region_views;
5994 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5995 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5997 midi_region_views.push_back (mrv);
6002 int const r = d.run ();
6003 if (r != RESPONSE_ACCEPT) {
6007 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6008 (*i)->midi_region()->transpose (d.semitones ());
6013 Editor::set_tempo_from_region ()
6015 RegionSelection rs = get_regions_from_selection_and_entered ();
6017 if (!_session || rs.empty()) {
6021 RegionView* rv = rs.front();
6023 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6027 Editor::use_range_as_bar ()
6029 framepos_t start, end;
6030 if (get_edit_op_range (start, end)) {
6031 define_one_bar (start, end);
6036 Editor::define_one_bar (framepos_t start, framepos_t end)
6038 framepos_t length = end - start;
6040 const Meter& m (_session->tempo_map().meter_at (start));
6042 /* length = 1 bar */
6044 /* now we want frames per beat.
6045 we have frames per bar, and beats per bar, so ...
6048 /* XXXX METER MATH */
6050 double frames_per_beat = length / m.divisions_per_bar();
6052 /* beats per minute = */
6054 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6056 /* now decide whether to:
6058 (a) set global tempo
6059 (b) add a new tempo marker
6063 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6065 bool do_global = false;
6067 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6069 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6070 at the start, or create a new marker
6073 vector<string> options;
6074 options.push_back (_("Cancel"));
6075 options.push_back (_("Add new marker"));
6076 options.push_back (_("Set global tempo"));
6079 _("Define one bar"),
6080 _("Do you want to set the global tempo or add a new tempo marker?"),
6084 c.set_default_response (2);
6100 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6101 if the marker is at the region starter, change it, otherwise add
6106 begin_reversible_command (_("set tempo from region"));
6107 XMLNode& before (_session->tempo_map().get_state());
6110 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6111 } else if (t.frame() == start) {
6112 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6114 Timecode::BBT_Time bbt;
6115 _session->tempo_map().bbt_time (start, bbt);
6116 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6119 XMLNode& after (_session->tempo_map().get_state());
6121 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6122 commit_reversible_command ();
6126 Editor::split_region_at_transients ()
6128 AnalysisFeatureList positions;
6130 RegionSelection rs = get_regions_from_selection_and_entered ();
6132 if (!_session || rs.empty()) {
6136 begin_reversible_command (_("split regions"));
6138 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6140 RegionSelection::iterator tmp;
6145 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6147 if (ar && (ar->get_transients (positions) == 0)) {
6148 split_region_at_points ((*i)->region(), positions, true);
6155 commit_reversible_command ();
6160 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6162 bool use_rhythmic_rodent = false;
6164 boost::shared_ptr<Playlist> pl = r->playlist();
6166 list<boost::shared_ptr<Region> > new_regions;
6172 if (positions.empty()) {
6177 if (positions.size() > 20 && can_ferret) {
6178 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);
6179 MessageDialog msg (msgstr,
6182 Gtk::BUTTONS_OK_CANCEL);
6185 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6186 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6188 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6191 msg.set_title (_("Excessive split?"));
6194 int response = msg.run();
6200 case RESPONSE_APPLY:
6201 use_rhythmic_rodent = true;
6208 if (use_rhythmic_rodent) {
6209 show_rhythm_ferret ();
6213 AnalysisFeatureList::const_iterator x;
6215 pl->clear_changes ();
6216 pl->clear_owned_changes ();
6218 x = positions.begin();
6220 if (x == positions.end()) {
6225 pl->remove_region (r);
6229 while (x != positions.end()) {
6231 /* deal with positons that are out of scope of present region bounds */
6232 if (*x <= 0 || *x > r->length()) {
6237 /* file start = original start + how far we from the initial position ?
6240 framepos_t file_start = r->start() + pos;
6242 /* length = next position - current position
6245 framepos_t len = (*x) - pos;
6247 /* XXX we do we really want to allow even single-sample regions?
6248 shouldn't we have some kind of lower limit on region size?
6257 if (RegionFactory::region_name (new_name, r->name())) {
6261 /* do NOT announce new regions 1 by one, just wait till they are all done */
6265 plist.add (ARDOUR::Properties::start, file_start);
6266 plist.add (ARDOUR::Properties::length, len);
6267 plist.add (ARDOUR::Properties::name, new_name);
6268 plist.add (ARDOUR::Properties::layer, 0);
6270 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6271 /* because we set annouce to false, manually add the new region to the
6274 RegionFactory::map_add (nr);
6276 pl->add_region (nr, r->position() + pos);
6279 new_regions.push_front(nr);
6288 RegionFactory::region_name (new_name, r->name());
6290 /* Add the final region */
6293 plist.add (ARDOUR::Properties::start, r->start() + pos);
6294 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6295 plist.add (ARDOUR::Properties::name, new_name);
6296 plist.add (ARDOUR::Properties::layer, 0);
6298 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6299 /* because we set annouce to false, manually add the new region to the
6302 RegionFactory::map_add (nr);
6303 pl->add_region (nr, r->position() + pos);
6306 new_regions.push_front(nr);
6311 /* We might have removed regions, which alters other regions' layering_index,
6312 so we need to do a recursive diff here.
6314 vector<Command*> cmds;
6316 _session->add_commands (cmds);
6318 _session->add_command (new StatefulDiffCommand (pl));
6322 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6323 set_selected_regionview_from_region_list ((*i), Selection::Add);
6329 Editor::place_transient()
6335 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6341 framepos_t where = get_preferred_edit_position();
6343 begin_reversible_command (_("place transient"));
6345 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6346 framepos_t position = (*r)->region()->position();
6347 (*r)->region()->add_transient(where - position);
6350 commit_reversible_command ();
6354 Editor::remove_transient(ArdourCanvas::Item* item)
6360 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6363 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6364 _arv->remove_transient (*(float*) _line->get_data ("position"));
6368 Editor::snap_regions_to_grid ()
6370 list <boost::shared_ptr<Playlist > > used_playlists;
6372 RegionSelection rs = get_regions_from_selection_and_entered ();
6374 if (!_session || rs.empty()) {
6378 begin_reversible_command (_("snap regions to grid"));
6380 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6382 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6384 if (!pl->frozen()) {
6385 /* we haven't seen this playlist before */
6387 /* remember used playlists so we can thaw them later */
6388 used_playlists.push_back(pl);
6392 framepos_t start_frame = (*r)->region()->first_frame ();
6393 snap_to (start_frame);
6394 (*r)->region()->set_position (start_frame);
6397 while (used_playlists.size() > 0) {
6398 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6400 used_playlists.pop_front();
6403 commit_reversible_command ();
6407 Editor::close_region_gaps ()
6409 list <boost::shared_ptr<Playlist > > used_playlists;
6411 RegionSelection rs = get_regions_from_selection_and_entered ();
6413 if (!_session || rs.empty()) {
6417 Dialog dialog (_("Close Region Gaps"));
6420 table.set_spacings (12);
6421 table.set_border_width (12);
6422 Label* l = manage (left_aligned_label (_("Crossfade length")));
6423 table.attach (*l, 0, 1, 0, 1);
6425 SpinButton spin_crossfade (1, 0);
6426 spin_crossfade.set_range (0, 15);
6427 spin_crossfade.set_increments (1, 1);
6428 spin_crossfade.set_value (5);
6429 table.attach (spin_crossfade, 1, 2, 0, 1);
6431 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6433 l = manage (left_aligned_label (_("Pull-back length")));
6434 table.attach (*l, 0, 1, 1, 2);
6436 SpinButton spin_pullback (1, 0);
6437 spin_pullback.set_range (0, 100);
6438 spin_pullback.set_increments (1, 1);
6439 spin_pullback.set_value(30);
6440 table.attach (spin_pullback, 1, 2, 1, 2);
6442 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6444 dialog.get_vbox()->pack_start (table);
6445 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6446 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6449 if (dialog.run () == RESPONSE_CANCEL) {
6453 framepos_t crossfade_len = spin_crossfade.get_value();
6454 framepos_t pull_back_frames = spin_pullback.get_value();
6456 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6457 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6459 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6461 begin_reversible_command (_("close region gaps"));
6464 boost::shared_ptr<Region> last_region;
6466 rs.sort_by_position_and_track();
6468 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6470 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6472 if (!pl->frozen()) {
6473 /* we haven't seen this playlist before */
6475 /* remember used playlists so we can thaw them later */
6476 used_playlists.push_back(pl);
6480 framepos_t position = (*r)->region()->position();
6482 if (idx == 0 || position < last_region->position()){
6483 last_region = (*r)->region();
6488 (*r)->region()->trim_front( (position - pull_back_frames));
6489 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6491 last_region = (*r)->region();
6496 while (used_playlists.size() > 0) {
6497 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6499 used_playlists.pop_front();
6502 commit_reversible_command ();
6506 Editor::tab_to_transient (bool forward)
6508 AnalysisFeatureList positions;
6510 RegionSelection rs = get_regions_from_selection_and_entered ();
6516 framepos_t pos = _session->audible_frame ();
6518 if (!selection->tracks.empty()) {
6520 /* don't waste time searching for transients in duplicate playlists.
6523 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6525 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6527 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6530 boost::shared_ptr<Track> tr = rtv->track();
6532 boost::shared_ptr<Playlist> pl = tr->playlist ();
6534 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6537 positions.push_back (result);
6550 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6551 (*r)->region()->get_transients (positions);
6555 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6558 AnalysisFeatureList::iterator x;
6560 for (x = positions.begin(); x != positions.end(); ++x) {
6566 if (x != positions.end ()) {
6567 _session->request_locate (*x);
6571 AnalysisFeatureList::reverse_iterator x;
6573 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6579 if (x != positions.rend ()) {
6580 _session->request_locate (*x);
6586 Editor::playhead_forward_to_grid ()
6592 framepos_t pos = playhead_cursor->current_frame ();
6593 if (pos < max_framepos - 1) {
6595 snap_to_internal (pos, RoundUpAlways, false);
6596 _session->request_locate (pos);
6602 Editor::playhead_backward_to_grid ()
6608 framepos_t pos = playhead_cursor->current_frame ();
6611 snap_to_internal (pos, RoundDownAlways, false);
6612 _session->request_locate (pos);
6617 Editor::set_track_height (Height h)
6619 TrackSelection& ts (selection->tracks);
6621 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6622 (*x)->set_height_enum (h);
6627 Editor::toggle_tracks_active ()
6629 TrackSelection& ts (selection->tracks);
6631 bool target = false;
6637 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6638 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6642 target = !rtv->_route->active();
6645 rtv->_route->set_active (target, this);
6651 Editor::remove_tracks ()
6653 TrackSelection& ts (selection->tracks);
6659 vector<string> choices;
6663 const char* trackstr;
6665 vector<boost::shared_ptr<Route> > routes;
6666 bool special_bus = false;
6668 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6669 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6673 if (rtv->is_track()) {
6678 routes.push_back (rtv->_route);
6680 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6685 if (special_bus && !Config->get_allow_special_bus_removal()) {
6686 MessageDialog msg (_("That would be bad news ...."),
6690 msg.set_secondary_text (string_compose (_(
6691 "Removing the master or monitor bus is such a bad idea\n\
6692 that %1 is not going to allow it.\n\
6694 If you really want to do this sort of thing\n\
6695 edit your ardour.rc file to set the\n\
6696 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6703 if (ntracks + nbusses == 0) {
6707 // XXX should be using gettext plural forms, maybe?
6709 trackstr = _("tracks");
6711 trackstr = _("track");
6715 busstr = _("busses");
6722 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6723 "(You may also lose the playlists associated with the %2)\n\n"
6724 "This action cannot be undone, and the session file will be overwritten!"),
6725 ntracks, trackstr, nbusses, busstr);
6727 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6728 "(You may also lose the playlists associated with the %2)\n\n"
6729 "This action cannot be undone, and the session file will be overwritten!"),
6732 } else if (nbusses) {
6733 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6734 "This action cannot be undone, and the session file will be overwritten"),
6738 choices.push_back (_("No, do nothing."));
6739 if (ntracks + nbusses > 1) {
6740 choices.push_back (_("Yes, remove them."));
6742 choices.push_back (_("Yes, remove it."));
6747 title = string_compose (_("Remove %1"), trackstr);
6749 title = string_compose (_("Remove %1"), busstr);
6752 Choice prompter (title, prompt, choices);
6754 if (prompter.run () != 1) {
6759 Session::StateProtector sp (_session);
6760 DisplaySuspender ds;
6761 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6762 _session->remove_route (*x);
6768 Editor::do_insert_time ()
6770 if (selection->tracks.empty()) {
6774 InsertTimeDialog d (*this);
6775 int response = d.run ();
6777 if (response != RESPONSE_OK) {
6781 if (d.distance() == 0) {
6785 InsertTimeOption opt = d.intersected_region_action ();
6788 get_preferred_edit_position(),
6794 d.move_glued_markers(),
6795 d.move_locked_markers(),
6801 Editor::insert_time (
6802 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6803 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6806 bool commit = false;
6808 if (Config->get_edit_mode() == Lock) {
6812 begin_reversible_command (_("insert time"));
6814 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6816 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6820 /* don't operate on any playlist more than once, which could
6821 * happen if "all playlists" is enabled, but there is more
6822 * than 1 track using playlists "from" a given track.
6825 set<boost::shared_ptr<Playlist> > pl;
6827 if (all_playlists) {
6828 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6830 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6831 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6836 if ((*x)->playlist ()) {
6837 pl.insert ((*x)->playlist ());
6841 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6843 (*i)->clear_changes ();
6844 (*i)->clear_owned_changes ();
6846 if (opt == SplitIntersected) {
6850 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6852 vector<Command*> cmds;
6854 _session->add_commands (cmds);
6856 _session->add_command (new StatefulDiffCommand (*i));
6861 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6863 rtav->route ()->shift (pos, frames);
6871 XMLNode& before (_session->locations()->get_state());
6872 Locations::LocationList copy (_session->locations()->list());
6874 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6876 Locations::LocationList::const_iterator tmp;
6878 bool const was_locked = (*i)->locked ();
6879 if (locked_markers_too) {
6883 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6885 if ((*i)->start() >= pos) {
6886 (*i)->set_start ((*i)->start() + frames);
6887 if (!(*i)->is_mark()) {
6888 (*i)->set_end ((*i)->end() + frames);
6901 XMLNode& after (_session->locations()->get_state());
6902 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6907 _session->tempo_map().insert_time (pos, frames);
6911 commit_reversible_command ();
6916 Editor::fit_selected_tracks ()
6918 if (!selection->tracks.empty()) {
6919 fit_tracks (selection->tracks);
6923 /* no selected tracks - use tracks with selected regions */
6925 if (!selection->regions.empty()) {
6926 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6927 tvl.push_back (&(*r)->get_time_axis_view ());
6933 } else if (internal_editing()) {
6934 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6937 if (entered_track) {
6938 tvl.push_back (entered_track);
6947 Editor::fit_tracks (TrackViewList & tracks)
6949 if (tracks.empty()) {
6953 uint32_t child_heights = 0;
6954 int visible_tracks = 0;
6956 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6958 if (!(*t)->marked_for_display()) {
6962 child_heights += (*t)->effective_height() - (*t)->current_height();
6966 /* compute the per-track height from:
6968 total canvas visible height -
6969 height that will be taken by visible children of selected
6970 tracks - height of the ruler/hscroll area
6972 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6973 double first_y_pos = DBL_MAX;
6975 if (h < TimeAxisView::preset_height (HeightSmall)) {
6976 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6977 /* too small to be displayed */
6981 undo_visual_stack.push_back (current_visual_state (true));
6982 no_save_visual = true;
6984 /* build a list of all tracks, including children */
6987 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6989 TimeAxisView::Children c = (*i)->get_child_list ();
6990 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6991 all.push_back (j->get());
6995 bool prev_was_selected = false;
6996 bool is_selected = tracks.contains (all.front());
6997 bool next_is_selected;
6999 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7001 TrackViewList::iterator next;
7006 if (next != all.end()) {
7007 next_is_selected = tracks.contains (*next);
7009 next_is_selected = false;
7012 if ((*t)->marked_for_display ()) {
7014 (*t)->set_height (h);
7015 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7017 if (prev_was_selected && next_is_selected) {
7018 hide_track_in_display (*t);
7023 prev_was_selected = is_selected;
7024 is_selected = next_is_selected;
7028 set the controls_layout height now, because waiting for its size
7029 request signal handler will cause the vertical adjustment setting to fail
7032 controls_layout.property_height () = _full_canvas_height;
7033 vertical_adjustment.set_value (first_y_pos);
7035 redo_visual_stack.push_back (current_visual_state (true));
7037 visible_tracks_selector.set_text (_("Sel"));
7041 Editor::save_visual_state (uint32_t n)
7043 while (visual_states.size() <= n) {
7044 visual_states.push_back (0);
7047 if (visual_states[n] != 0) {
7048 delete visual_states[n];
7051 visual_states[n] = current_visual_state (true);
7056 Editor::goto_visual_state (uint32_t n)
7058 if (visual_states.size() <= n) {
7062 if (visual_states[n] == 0) {
7066 use_visual_state (*visual_states[n]);
7070 Editor::start_visual_state_op (uint32_t n)
7072 save_visual_state (n);
7074 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7076 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7077 pup->set_text (buf);
7082 Editor::cancel_visual_state_op (uint32_t n)
7084 goto_visual_state (n);
7088 Editor::toggle_region_mute ()
7090 if (_ignore_region_action) {
7094 RegionSelection rs = get_regions_from_selection_and_entered ();
7100 if (rs.size() > 1) {
7101 begin_reversible_command (_("mute regions"));
7103 begin_reversible_command (_("mute region"));
7106 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7108 (*i)->region()->playlist()->clear_changes ();
7109 (*i)->region()->set_muted (!(*i)->region()->muted ());
7110 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7114 commit_reversible_command ();
7118 Editor::combine_regions ()
7120 /* foreach track with selected regions, take all selected regions
7121 and join them into a new region containing the subregions (as a
7125 typedef set<RouteTimeAxisView*> RTVS;
7128 if (selection->regions.empty()) {
7132 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7133 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7136 tracks.insert (rtv);
7140 begin_reversible_command (_("combine regions"));
7142 vector<RegionView*> new_selection;
7144 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7147 if ((rv = (*i)->combine_regions ()) != 0) {
7148 new_selection.push_back (rv);
7152 selection->clear_regions ();
7153 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7154 selection->add (*i);
7157 commit_reversible_command ();
7161 Editor::uncombine_regions ()
7163 typedef set<RouteTimeAxisView*> RTVS;
7166 if (selection->regions.empty()) {
7170 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7171 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7174 tracks.insert (rtv);
7178 begin_reversible_command (_("uncombine regions"));
7180 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7181 (*i)->uncombine_regions ();
7184 commit_reversible_command ();
7188 Editor::toggle_midi_input_active (bool flip_others)
7191 boost::shared_ptr<RouteList> rl (new RouteList);
7193 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7194 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7200 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7203 rl->push_back (rtav->route());
7204 onoff = !mt->input_active();
7208 _session->set_exclusive_input_active (rl, onoff, flip_others);
7215 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7217 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7218 lock_dialog->get_vbox()->pack_start (*padlock);
7220 ArdourButton* b = manage (new ArdourButton);
7221 b->set_name ("lock button");
7222 b->set_text (_("Click to unlock"));
7223 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7224 lock_dialog->get_vbox()->pack_start (*b);
7226 lock_dialog->get_vbox()->show_all ();
7227 lock_dialog->set_size_request (200, 200);
7231 /* The global menu bar continues to be accessible to applications
7232 with modal dialogs, which means that we need to desensitize
7233 all items in the menu bar. Since those items are really just
7234 proxies for actions, that means disabling all actions.
7236 ActionManager::disable_all_actions ();
7238 lock_dialog->present ();
7244 lock_dialog->hide ();
7247 ActionManager::pop_action_state ();
7250 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7251 start_lock_event_timing ();
7256 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7258 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7262 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7264 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7265 Gtkmm2ext::UI::instance()->flush_pending ();
7269 Editor::bring_all_sources_into_session ()
7276 ArdourDialog w (_("Moving embedded files into session folder"));
7277 w.get_vbox()->pack_start (msg);
7280 /* flush all pending GUI events because we're about to start copying
7284 Gtkmm2ext::UI::instance()->flush_pending ();
7288 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));