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 RegionSelection rs = get_regions_from_selection_and_entered ();
1721 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1723 if ((*i)->region()->position() < start) {
1724 start = (*i)->region()->position();
1727 if ((*i)->region()->last_frame() + 1 > end) {
1728 end = (*i)->region()->last_frame() + 1;
1731 tracks.insert (&((*i)->get_time_axis_view()));
1734 if ((start == 0 && end == 0) || end < start) {
1738 calc_extra_zoom_edges (start, end);
1740 /* if we're zooming on both axes we need to save track heights etc.
1743 undo_visual_stack.push_back (current_visual_state (both_axes));
1745 PBD::Unwinder<bool> nsv (no_save_visual, true);
1747 temporal_zoom_by_frame (start, end);
1750 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1752 /* set visible track heights appropriately */
1754 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1755 (*t)->set_height (per_track_height);
1758 /* hide irrelevant tracks */
1760 DisplaySuspender ds;
1762 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1763 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1764 hide_track_in_display (*i);
1768 vertical_adjustment.set_value (0.0);
1771 redo_visual_stack.push_back (current_visual_state (both_axes));
1776 Editor::temporal_zoom_selection (bool both_axes)
1778 if (!selection) return;
1780 //ToDo: if notes are selected, zoom to that
1782 //ToDo: if control points are selected, zoom to that
1784 //if region(s) are selected, zoom to that
1785 if ( !selection->regions.empty() )
1786 temporal_zoom_region (both_axes);
1788 //if a range is selected, zoom to that
1789 if (!selection->time.empty()) {
1791 framepos_t start = selection->time.start();
1792 framepos_t end = selection->time.end_frame();
1794 calc_extra_zoom_edges(start, end);
1796 temporal_zoom_by_frame (start, end);
1799 fit_selected_tracks();
1806 Editor::temporal_zoom_session ()
1808 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1811 framecnt_t start = _session->current_start_frame();
1812 framecnt_t end = _session->current_end_frame();
1814 if (_session->actively_recording () ) {
1815 framepos_t cur = playhead_cursor->current_frame ();
1817 /* recording beyond the end marker; zoom out
1818 * by 5 seconds more so that if 'follow
1819 * playhead' is active we don't immediately
1822 end = cur + _session->frame_rate() * 5;
1826 if ((start == 0 && end == 0) || end < start) {
1830 calc_extra_zoom_edges(start, end);
1832 temporal_zoom_by_frame (start, end);
1837 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1839 if (!_session) return;
1841 if ((start == 0 && end == 0) || end < start) {
1845 framepos_t range = end - start;
1847 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1849 framepos_t new_page = range;
1850 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1851 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1853 if (new_leftmost > middle) {
1857 if (new_leftmost < 0) {
1861 reposition_and_zoom (new_leftmost, new_fpp);
1865 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1871 framecnt_t range_before = frame - leftmost_frame;
1875 if (samples_per_pixel <= 1) {
1878 new_spp = samples_per_pixel + (samples_per_pixel/2);
1880 range_before += range_before/2;
1882 if (samples_per_pixel >= 1) {
1883 new_spp = samples_per_pixel - (samples_per_pixel/2);
1885 /* could bail out here since we cannot zoom any finer,
1886 but leave that to the equality test below
1888 new_spp = samples_per_pixel;
1891 range_before -= range_before/2;
1894 if (new_spp == samples_per_pixel) {
1898 /* zoom focus is automatically taken as @param frame when this
1902 framepos_t new_leftmost = frame - (framepos_t)range_before;
1904 if (new_leftmost > frame) {
1908 if (new_leftmost < 0) {
1912 reposition_and_zoom (new_leftmost, new_spp);
1917 Editor::choose_new_marker_name(string &name) {
1919 if (!ARDOUR_UI::config()->get_name_new_markers()) {
1920 /* don't prompt user for a new name */
1924 ArdourPrompter dialog (true);
1926 dialog.set_prompt (_("New Name:"));
1928 dialog.set_title (_("New Location Marker"));
1930 dialog.set_name ("MarkNameWindow");
1931 dialog.set_size_request (250, -1);
1932 dialog.set_position (Gtk::WIN_POS_MOUSE);
1934 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1935 dialog.set_initial_text (name);
1939 switch (dialog.run ()) {
1940 case RESPONSE_ACCEPT:
1946 dialog.get_result(name);
1953 Editor::add_location_from_selection ()
1957 if (selection->time.empty()) {
1961 if (_session == 0 || clicked_axisview == 0) {
1965 framepos_t start = selection->time[clicked_selection].start;
1966 framepos_t end = selection->time[clicked_selection].end;
1968 _session->locations()->next_available_name(rangename,"selection");
1969 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1971 begin_reversible_command (_("add marker"));
1973 XMLNode &before = _session->locations()->get_state();
1974 _session->locations()->add (location, true);
1975 XMLNode &after = _session->locations()->get_state();
1976 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1978 commit_reversible_command ();
1982 Editor::add_location_mark (framepos_t where)
1986 select_new_marker = true;
1988 _session->locations()->next_available_name(markername,"mark");
1989 if (!choose_new_marker_name(markername)) {
1992 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1993 begin_reversible_command (_("add marker"));
1995 XMLNode &before = _session->locations()->get_state();
1996 _session->locations()->add (location, true);
1997 XMLNode &after = _session->locations()->get_state();
1998 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2000 commit_reversible_command ();
2004 Editor::add_location_from_playhead_cursor ()
2006 add_location_mark (_session->audible_frame());
2010 Editor::remove_location_at_playhead_cursor ()
2015 begin_reversible_command (_("remove marker"));
2017 XMLNode &before = _session->locations()->get_state();
2018 bool removed = false;
2020 //find location(s) at this time
2021 Locations::LocationList locs;
2022 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2023 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2024 if ((*i)->is_mark()) {
2025 _session->locations()->remove (*i);
2032 XMLNode &after = _session->locations()->get_state();
2033 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2035 commit_reversible_command ();
2040 /** Add a range marker around each selected region */
2042 Editor::add_locations_from_region ()
2044 RegionSelection rs = get_regions_from_selection_and_entered ();
2050 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2052 XMLNode &before = _session->locations()->get_state();
2054 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2056 boost::shared_ptr<Region> region = (*i)->region ();
2058 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2060 _session->locations()->add (location, true);
2063 XMLNode &after = _session->locations()->get_state();
2064 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2066 commit_reversible_command ();
2069 /** Add a single range marker around all selected regions */
2071 Editor::add_location_from_region ()
2073 RegionSelection rs = get_regions_from_selection_and_entered ();
2079 begin_reversible_command (_("add marker"));
2081 XMLNode &before = _session->locations()->get_state();
2085 if (rs.size() > 1) {
2086 _session->locations()->next_available_name(markername, "regions");
2088 RegionView* rv = *(rs.begin());
2089 boost::shared_ptr<Region> region = rv->region();
2090 markername = region->name();
2093 if (!choose_new_marker_name(markername)) {
2097 // single range spanning all selected
2098 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2099 _session->locations()->add (location, true);
2101 XMLNode &after = _session->locations()->get_state();
2102 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2104 commit_reversible_command ();
2110 Editor::jump_forward_to_mark ()
2116 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2122 _session->request_locate (pos, _session->transport_rolling());
2126 Editor::jump_backward_to_mark ()
2132 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2138 _session->request_locate (pos, _session->transport_rolling());
2144 framepos_t const pos = _session->audible_frame ();
2147 _session->locations()->next_available_name (markername, "mark");
2149 if (!choose_new_marker_name (markername)) {
2153 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2157 Editor::clear_markers ()
2160 begin_reversible_command (_("clear markers"));
2162 XMLNode &before = _session->locations()->get_state();
2163 _session->locations()->clear_markers ();
2164 XMLNode &after = _session->locations()->get_state();
2165 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2167 commit_reversible_command ();
2172 Editor::clear_ranges ()
2175 begin_reversible_command (_("clear ranges"));
2177 XMLNode &before = _session->locations()->get_state();
2179 _session->locations()->clear_ranges ();
2181 XMLNode &after = _session->locations()->get_state();
2182 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2184 commit_reversible_command ();
2189 Editor::clear_locations ()
2191 begin_reversible_command (_("clear locations"));
2193 XMLNode &before = _session->locations()->get_state();
2194 _session->locations()->clear ();
2195 XMLNode &after = _session->locations()->get_state();
2196 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2198 commit_reversible_command ();
2202 Editor::unhide_markers ()
2204 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2205 Location *l = (*i).first;
2206 if (l->is_hidden() && l->is_mark()) {
2207 l->set_hidden(false, this);
2213 Editor::unhide_ranges ()
2215 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2216 Location *l = (*i).first;
2217 if (l->is_hidden() && l->is_range_marker()) {
2218 l->set_hidden(false, this);
2223 /* INSERT/REPLACE */
2226 Editor::insert_region_list_selection (float times)
2228 RouteTimeAxisView *tv = 0;
2229 boost::shared_ptr<Playlist> playlist;
2231 if (clicked_routeview != 0) {
2232 tv = clicked_routeview;
2233 } else if (!selection->tracks.empty()) {
2234 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2237 } else if (entered_track != 0) {
2238 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2245 if ((playlist = tv->playlist()) == 0) {
2249 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2254 begin_reversible_command (_("insert region"));
2255 playlist->clear_changes ();
2256 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2257 if (Config->get_edit_mode() == Ripple)
2258 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2260 _session->add_command(new StatefulDiffCommand (playlist));
2261 commit_reversible_command ();
2264 /* BUILT-IN EFFECTS */
2267 Editor::reverse_selection ()
2272 /* GAIN ENVELOPE EDITING */
2275 Editor::edit_envelope ()
2282 Editor::transition_to_rolling (bool fwd)
2288 if (_session->config.get_external_sync()) {
2289 switch (Config->get_sync_source()) {
2293 /* transport controlled by the master */
2298 if (_session->is_auditioning()) {
2299 _session->cancel_audition ();
2303 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2307 Editor::play_from_start ()
2309 _session->request_locate (_session->current_start_frame(), true);
2313 Editor::play_from_edit_point ()
2315 _session->request_locate (get_preferred_edit_position(), true);
2319 Editor::play_from_edit_point_and_return ()
2321 framepos_t start_frame;
2322 framepos_t return_frame;
2324 start_frame = get_preferred_edit_position (true);
2326 if (_session->transport_rolling()) {
2327 _session->request_locate (start_frame, false);
2331 /* don't reset the return frame if its already set */
2333 if ((return_frame = _session->requested_return_frame()) < 0) {
2334 return_frame = _session->audible_frame();
2337 if (start_frame >= 0) {
2338 _session->request_roll_at_and_return (start_frame, return_frame);
2343 Editor::play_selection ()
2345 if (selection->time.empty()) {
2349 _session->request_play_range (&selection->time, true);
2353 Editor::get_preroll ()
2355 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2360 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2362 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2365 location -= get_preroll();
2367 //don't try to locate before the beginning of time
2371 //if follow_playhead is on, keep the playhead on the screen
2372 if ( _follow_playhead )
2373 if ( location < leftmost_frame )
2374 location = leftmost_frame;
2376 _session->request_locate( location );
2380 Editor::play_with_preroll ()
2382 if (selection->time.empty()) {
2385 framepos_t preroll = get_preroll();
2387 framepos_t start = 0;
2388 if (selection->time[clicked_selection].start > preroll)
2389 start = selection->time[clicked_selection].start - preroll;
2391 framepos_t end = selection->time[clicked_selection].end + preroll;
2393 AudioRange ar (start, end, 0);
2394 list<AudioRange> lar;
2397 _session->request_play_range (&lar, true);
2402 Editor::play_location (Location& location)
2404 if (location.start() <= location.end()) {
2408 _session->request_bounded_roll (location.start(), location.end());
2412 Editor::loop_location (Location& location)
2414 if (location.start() <= location.end()) {
2420 if ((tll = transport_loop_location()) != 0) {
2421 tll->set (location.start(), location.end());
2423 // enable looping, reposition and start rolling
2424 _session->request_locate (tll->start(), true);
2425 _session->request_play_loop (true);
2430 Editor::do_layer_operation (LayerOperation op)
2432 if (selection->regions.empty ()) {
2436 bool const multiple = selection->regions.size() > 1;
2440 begin_reversible_command (_("raise regions"));
2442 begin_reversible_command (_("raise region"));
2448 begin_reversible_command (_("raise regions to top"));
2450 begin_reversible_command (_("raise region to top"));
2456 begin_reversible_command (_("lower regions"));
2458 begin_reversible_command (_("lower region"));
2464 begin_reversible_command (_("lower regions to bottom"));
2466 begin_reversible_command (_("lower region"));
2471 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2472 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2473 (*i)->clear_owned_changes ();
2476 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2477 boost::shared_ptr<Region> r = (*i)->region ();
2489 r->lower_to_bottom ();
2493 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2494 vector<Command*> cmds;
2496 _session->add_commands (cmds);
2499 commit_reversible_command ();
2503 Editor::raise_region ()
2505 do_layer_operation (Raise);
2509 Editor::raise_region_to_top ()
2511 do_layer_operation (RaiseToTop);
2515 Editor::lower_region ()
2517 do_layer_operation (Lower);
2521 Editor::lower_region_to_bottom ()
2523 do_layer_operation (LowerToBottom);
2526 /** Show the region editor for the selected regions */
2528 Editor::show_region_properties ()
2530 selection->foreach_regionview (&RegionView::show_region_editor);
2533 /** Show the midi list editor for the selected MIDI regions */
2535 Editor::show_midi_list_editor ()
2537 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2541 Editor::rename_region ()
2543 RegionSelection rs = get_regions_from_selection_and_entered ();
2549 ArdourDialog d (*this, _("Rename Region"), true, false);
2551 Label label (_("New name:"));
2554 hbox.set_spacing (6);
2555 hbox.pack_start (label, false, false);
2556 hbox.pack_start (entry, true, true);
2558 d.get_vbox()->set_border_width (12);
2559 d.get_vbox()->pack_start (hbox, false, false);
2561 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2562 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2564 d.set_size_request (300, -1);
2566 entry.set_text (rs.front()->region()->name());
2567 entry.select_region (0, -1);
2569 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2575 int const ret = d.run();
2579 if (ret != RESPONSE_OK) {
2583 std::string str = entry.get_text();
2584 strip_whitespace_edges (str);
2586 rs.front()->region()->set_name (str);
2587 _regions->redisplay ();
2592 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2594 if (_session->is_auditioning()) {
2595 _session->cancel_audition ();
2598 // note: some potential for creativity here, because region doesn't
2599 // have to belong to the playlist that Route is handling
2601 // bool was_soloed = route.soloed();
2603 route.set_solo (true, this);
2605 _session->request_bounded_roll (region->position(), region->position() + region->length());
2607 /* XXX how to unset the solo state ? */
2610 /** Start an audition of the first selected region */
2612 Editor::play_edit_range ()
2614 framepos_t start, end;
2616 if (get_edit_op_range (start, end)) {
2617 _session->request_bounded_roll (start, end);
2622 Editor::play_selected_region ()
2624 framepos_t start = max_framepos;
2627 RegionSelection rs = get_regions_from_selection_and_entered ();
2633 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2634 if ((*i)->region()->position() < start) {
2635 start = (*i)->region()->position();
2637 if ((*i)->region()->last_frame() + 1 > end) {
2638 end = (*i)->region()->last_frame() + 1;
2642 _session->request_bounded_roll (start, end);
2646 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2648 _session->audition_region (region);
2652 Editor::region_from_selection ()
2654 if (clicked_axisview == 0) {
2658 if (selection->time.empty()) {
2662 framepos_t start = selection->time[clicked_selection].start;
2663 framepos_t end = selection->time[clicked_selection].end;
2665 TrackViewList tracks = get_tracks_for_range_action ();
2667 framepos_t selection_cnt = end - start + 1;
2669 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2670 boost::shared_ptr<Region> current;
2671 boost::shared_ptr<Playlist> pl;
2672 framepos_t internal_start;
2675 if ((pl = (*i)->playlist()) == 0) {
2679 if ((current = pl->top_region_at (start)) == 0) {
2683 internal_start = start - current->position();
2684 RegionFactory::region_name (new_name, current->name(), true);
2688 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2689 plist.add (ARDOUR::Properties::length, selection_cnt);
2690 plist.add (ARDOUR::Properties::name, new_name);
2691 plist.add (ARDOUR::Properties::layer, 0);
2693 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2698 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2700 if (selection->time.empty() || selection->tracks.empty()) {
2704 framepos_t start, end;
2705 if (clicked_selection) {
2706 start = selection->time[clicked_selection].start;
2707 end = selection->time[clicked_selection].end;
2709 start = selection->time.start();
2710 end = selection->time.end_frame();
2713 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2714 sort_track_selection (ts);
2716 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2717 boost::shared_ptr<Region> current;
2718 boost::shared_ptr<Playlist> playlist;
2719 framepos_t internal_start;
2722 if ((playlist = (*i)->playlist()) == 0) {
2726 if ((current = playlist->top_region_at(start)) == 0) {
2730 internal_start = start - current->position();
2731 RegionFactory::region_name (new_name, current->name(), true);
2735 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2736 plist.add (ARDOUR::Properties::length, end - start + 1);
2737 plist.add (ARDOUR::Properties::name, new_name);
2739 new_regions.push_back (RegionFactory::create (current, plist));
2744 Editor::split_multichannel_region ()
2746 RegionSelection rs = get_regions_from_selection_and_entered ();
2752 vector< boost::shared_ptr<Region> > v;
2754 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2755 (*x)->region()->separate_by_channel (*_session, v);
2760 Editor::new_region_from_selection ()
2762 region_from_selection ();
2763 cancel_selection ();
2767 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2769 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2770 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2771 case Evoral::OverlapNone:
2779 * - selected tracks, or if there are none...
2780 * - tracks containing selected regions, or if there are none...
2785 Editor::get_tracks_for_range_action () const
2789 if (selection->tracks.empty()) {
2791 /* use tracks with selected regions */
2793 RegionSelection rs = selection->regions;
2795 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2796 TimeAxisView* tv = &(*i)->get_time_axis_view();
2798 if (!t.contains (tv)) {
2804 /* no regions and no tracks: use all tracks */
2810 t = selection->tracks;
2813 return t.filter_to_unique_playlists();
2817 Editor::separate_regions_between (const TimeSelection& ts)
2819 bool in_command = false;
2820 boost::shared_ptr<Playlist> playlist;
2821 RegionSelection new_selection;
2823 TrackViewList tmptracks = get_tracks_for_range_action ();
2824 sort_track_selection (tmptracks);
2826 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2828 RouteTimeAxisView* rtv;
2830 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2832 if (rtv->is_track()) {
2834 /* no edits to destructive tracks */
2836 if (rtv->track()->destructive()) {
2840 if ((playlist = rtv->playlist()) != 0) {
2842 playlist->clear_changes ();
2844 /* XXX need to consider musical time selections here at some point */
2846 double speed = rtv->track()->speed();
2849 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2851 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2852 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2854 latest_regionviews.clear ();
2856 playlist->partition ((framepos_t)((*t).start * speed),
2857 (framepos_t)((*t).end * speed), false);
2861 if (!latest_regionviews.empty()) {
2863 rtv->view()->foreach_regionview (sigc::bind (
2864 sigc::ptr_fun (add_if_covered),
2865 &(*t), &new_selection));
2868 begin_reversible_command (_("separate"));
2872 /* pick up changes to existing regions */
2874 vector<Command*> cmds;
2875 playlist->rdiff (cmds);
2876 _session->add_commands (cmds);
2878 /* pick up changes to the playlist itself (adds/removes)
2881 _session->add_command(new StatefulDiffCommand (playlist));
2890 // selection->set (new_selection);
2892 commit_reversible_command ();
2896 struct PlaylistState {
2897 boost::shared_ptr<Playlist> playlist;
2901 /** Take tracks from get_tracks_for_range_action and cut any regions
2902 * on those tracks so that the tracks are empty over the time
2906 Editor::separate_region_from_selection ()
2908 /* preferentially use *all* ranges in the time selection if we're in range mode
2909 to allow discontiguous operation, since get_edit_op_range() currently
2910 returns a single range.
2913 if (!selection->time.empty()) {
2915 separate_regions_between (selection->time);
2922 if (get_edit_op_range (start, end)) {
2924 AudioRange ar (start, end, 1);
2928 separate_regions_between (ts);
2934 Editor::separate_region_from_punch ()
2936 Location* loc = _session->locations()->auto_punch_location();
2938 separate_regions_using_location (*loc);
2943 Editor::separate_region_from_loop ()
2945 Location* loc = _session->locations()->auto_loop_location();
2947 separate_regions_using_location (*loc);
2952 Editor::separate_regions_using_location (Location& loc)
2954 if (loc.is_mark()) {
2958 AudioRange ar (loc.start(), loc.end(), 1);
2963 separate_regions_between (ts);
2966 /** Separate regions under the selected region */
2968 Editor::separate_under_selected_regions ()
2970 vector<PlaylistState> playlists;
2974 rs = get_regions_from_selection_and_entered();
2976 if (!_session || rs.empty()) {
2980 begin_reversible_command (_("separate region under"));
2982 list<boost::shared_ptr<Region> > regions_to_remove;
2984 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2985 // we can't just remove the region(s) in this loop because
2986 // this removes them from the RegionSelection, and they thus
2987 // disappear from underneath the iterator, and the ++i above
2988 // SEGVs in a puzzling fashion.
2990 // so, first iterate over the regions to be removed from rs and
2991 // add them to the regions_to_remove list, and then
2992 // iterate over the list to actually remove them.
2994 regions_to_remove.push_back ((*i)->region());
2997 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2999 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3002 // is this check necessary?
3006 vector<PlaylistState>::iterator i;
3008 //only take state if this is a new playlist.
3009 for (i = playlists.begin(); i != playlists.end(); ++i) {
3010 if ((*i).playlist == playlist) {
3015 if (i == playlists.end()) {
3017 PlaylistState before;
3018 before.playlist = playlist;
3019 before.before = &playlist->get_state();
3021 playlist->freeze ();
3022 playlists.push_back(before);
3025 //Partition on the region bounds
3026 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3028 //Re-add region that was just removed due to the partition operation
3029 playlist->add_region( (*rl), (*rl)->first_frame() );
3032 vector<PlaylistState>::iterator pl;
3034 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3035 (*pl).playlist->thaw ();
3036 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3039 commit_reversible_command ();
3043 Editor::crop_region_to_selection ()
3045 if (!selection->time.empty()) {
3047 crop_region_to (selection->time.start(), selection->time.end_frame());
3054 if (get_edit_op_range (start, end)) {
3055 crop_region_to (start, end);
3062 Editor::crop_region_to (framepos_t start, framepos_t end)
3064 vector<boost::shared_ptr<Playlist> > playlists;
3065 boost::shared_ptr<Playlist> playlist;
3068 if (selection->tracks.empty()) {
3069 ts = track_views.filter_to_unique_playlists();
3071 ts = selection->tracks.filter_to_unique_playlists ();
3074 sort_track_selection (ts);
3076 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3078 RouteTimeAxisView* rtv;
3080 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3082 boost::shared_ptr<Track> t = rtv->track();
3084 if (t != 0 && ! t->destructive()) {
3086 if ((playlist = rtv->playlist()) != 0) {
3087 playlists.push_back (playlist);
3093 if (playlists.empty()) {
3097 framepos_t the_start;
3101 begin_reversible_command (_("trim to selection"));
3103 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3105 boost::shared_ptr<Region> region;
3109 if ((region = (*i)->top_region_at(the_start)) == 0) {
3113 /* now adjust lengths to that we do the right thing
3114 if the selection extends beyond the region
3117 the_start = max (the_start, (framepos_t) region->position());
3118 if (max_framepos - the_start < region->length()) {
3119 the_end = the_start + region->length() - 1;
3121 the_end = max_framepos;
3123 the_end = min (end, the_end);
3124 cnt = the_end - the_start + 1;
3126 region->clear_changes ();
3127 region->trim_to (the_start, cnt);
3128 _session->add_command (new StatefulDiffCommand (region));
3131 commit_reversible_command ();
3135 Editor::region_fill_track ()
3137 RegionSelection rs = get_regions_from_selection_and_entered ();
3139 if (!_session || rs.empty()) {
3143 framepos_t const end = _session->current_end_frame ();
3145 begin_reversible_command (Operations::region_fill);
3147 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3149 boost::shared_ptr<Region> region ((*i)->region());
3151 boost::shared_ptr<Playlist> pl = region->playlist();
3153 if (end <= region->last_frame()) {
3157 double times = (double) (end - region->last_frame()) / (double) region->length();
3163 pl->clear_changes ();
3164 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3165 _session->add_command (new StatefulDiffCommand (pl));
3168 commit_reversible_command ();
3172 Editor::region_fill_selection ()
3174 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3178 if (selection->time.empty()) {
3182 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3187 framepos_t start = selection->time[clicked_selection].start;
3188 framepos_t end = selection->time[clicked_selection].end;
3190 boost::shared_ptr<Playlist> playlist;
3192 if (selection->tracks.empty()) {
3196 framepos_t selection_length = end - start;
3197 float times = (float)selection_length / region->length();
3199 begin_reversible_command (Operations::fill_selection);
3201 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3203 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3205 if ((playlist = (*i)->playlist()) == 0) {
3209 playlist->clear_changes ();
3210 playlist->add_region (RegionFactory::create (region, true), start, times);
3211 _session->add_command (new StatefulDiffCommand (playlist));
3214 commit_reversible_command ();
3218 Editor::set_region_sync_position ()
3220 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3224 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3226 bool in_command = false;
3228 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3230 if (!(*r)->region()->covers (where)) {
3234 boost::shared_ptr<Region> region ((*r)->region());
3237 begin_reversible_command (_("set sync point"));
3241 region->clear_changes ();
3242 region->set_sync_position (where);
3243 _session->add_command(new StatefulDiffCommand (region));
3247 commit_reversible_command ();
3251 /** Remove the sync positions of the selection */
3253 Editor::remove_region_sync ()
3255 RegionSelection rs = get_regions_from_selection_and_entered ();
3261 begin_reversible_command (_("remove region sync"));
3263 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3265 (*i)->region()->clear_changes ();
3266 (*i)->region()->clear_sync_position ();
3267 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3270 commit_reversible_command ();
3274 Editor::naturalize_region ()
3276 RegionSelection rs = get_regions_from_selection_and_entered ();
3282 if (rs.size() > 1) {
3283 begin_reversible_command (_("move regions to original position"));
3285 begin_reversible_command (_("move region to original position"));
3288 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3289 (*i)->region()->clear_changes ();
3290 (*i)->region()->move_to_natural_position ();
3291 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3294 commit_reversible_command ();
3298 Editor::align_regions (RegionPoint what)
3300 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3306 begin_reversible_command (_("align selection"));
3308 framepos_t const position = get_preferred_edit_position ();
3310 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3311 align_region_internal ((*i)->region(), what, position);
3314 commit_reversible_command ();
3317 struct RegionSortByTime {
3318 bool operator() (const RegionView* a, const RegionView* b) {
3319 return a->region()->position() < b->region()->position();
3324 Editor::align_regions_relative (RegionPoint point)
3326 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3332 framepos_t const position = get_preferred_edit_position ();
3334 framepos_t distance = 0;
3338 list<RegionView*> sorted;
3339 rs.by_position (sorted);
3341 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3346 if (position > r->position()) {
3347 distance = position - r->position();
3349 distance = r->position() - position;
3355 if (position > r->last_frame()) {
3356 distance = position - r->last_frame();
3357 pos = r->position() + distance;
3359 distance = r->last_frame() - position;
3360 pos = r->position() - distance;
3366 pos = r->adjust_to_sync (position);
3367 if (pos > r->position()) {
3368 distance = pos - r->position();
3370 distance = r->position() - pos;
3376 if (pos == r->position()) {
3380 begin_reversible_command (_("align selection (relative)"));
3382 /* move first one specially */
3384 r->clear_changes ();
3385 r->set_position (pos);
3386 _session->add_command(new StatefulDiffCommand (r));
3388 /* move rest by the same amount */
3392 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3394 boost::shared_ptr<Region> region ((*i)->region());
3396 region->clear_changes ();
3399 region->set_position (region->position() + distance);
3401 region->set_position (region->position() - distance);
3404 _session->add_command(new StatefulDiffCommand (region));
3408 commit_reversible_command ();
3412 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3414 begin_reversible_command (_("align region"));
3415 align_region_internal (region, point, position);
3416 commit_reversible_command ();
3420 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3422 region->clear_changes ();
3426 region->set_position (region->adjust_to_sync (position));
3430 if (position > region->length()) {
3431 region->set_position (position - region->length());
3436 region->set_position (position);
3440 _session->add_command(new StatefulDiffCommand (region));
3444 Editor::trim_region_front ()
3450 Editor::trim_region_back ()
3452 trim_region (false);
3456 Editor::trim_region (bool front)
3458 framepos_t where = get_preferred_edit_position();
3459 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3465 begin_reversible_command (front ? _("trim front") : _("trim back"));
3467 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3468 if (!(*i)->region()->locked()) {
3470 (*i)->region()->clear_changes ();
3473 (*i)->region()->trim_front (where);
3474 maybe_locate_with_edit_preroll ( where );
3476 (*i)->region()->trim_end (where);
3477 maybe_locate_with_edit_preroll ( where );
3480 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3484 commit_reversible_command ();
3487 /** Trim the end of the selected regions to the position of the edit cursor */
3489 Editor::trim_region_to_loop ()
3491 Location* loc = _session->locations()->auto_loop_location();
3495 trim_region_to_location (*loc, _("trim to loop"));
3499 Editor::trim_region_to_punch ()
3501 Location* loc = _session->locations()->auto_punch_location();
3505 trim_region_to_location (*loc, _("trim to punch"));
3509 Editor::trim_region_to_location (const Location& loc, const char* str)
3511 RegionSelection rs = get_regions_from_selection_and_entered ();
3513 begin_reversible_command (str);
3515 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3516 RegionView* rv = (*x);
3518 /* require region to span proposed trim */
3519 switch (rv->region()->coverage (loc.start(), loc.end())) {
3520 case Evoral::OverlapInternal:
3526 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3535 if (tav->track() != 0) {
3536 speed = tav->track()->speed();
3539 start = session_frame_to_track_frame (loc.start(), speed);
3540 end = session_frame_to_track_frame (loc.end(), speed);
3542 rv->region()->clear_changes ();
3543 rv->region()->trim_to (start, (end - start));
3544 _session->add_command(new StatefulDiffCommand (rv->region()));
3547 commit_reversible_command ();
3551 Editor::trim_region_to_previous_region_end ()
3553 return trim_to_region(false);
3557 Editor::trim_region_to_next_region_start ()
3559 return trim_to_region(true);
3563 Editor::trim_to_region(bool forward)
3565 RegionSelection rs = get_regions_from_selection_and_entered ();
3567 begin_reversible_command (_("trim to region"));
3569 boost::shared_ptr<Region> next_region;
3571 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3573 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3579 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3587 if (atav->track() != 0) {
3588 speed = atav->track()->speed();
3592 boost::shared_ptr<Region> region = arv->region();
3593 boost::shared_ptr<Playlist> playlist (region->playlist());
3595 region->clear_changes ();
3599 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3605 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3606 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3610 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3616 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3618 arv->region_changed (ARDOUR::bounds_change);
3621 _session->add_command(new StatefulDiffCommand (region));
3624 commit_reversible_command ();
3628 Editor::unfreeze_route ()
3630 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3634 clicked_routeview->track()->unfreeze ();
3638 Editor::_freeze_thread (void* arg)
3640 return static_cast<Editor*>(arg)->freeze_thread ();
3644 Editor::freeze_thread ()
3646 /* create event pool because we may need to talk to the session */
3647 SessionEvent::create_per_thread_pool ("freeze events", 64);
3648 /* create per-thread buffers for process() tree to use */
3649 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3650 current_interthread_info->done = true;
3655 Editor::freeze_route ()
3661 /* stop transport before we start. this is important */
3663 _session->request_transport_speed (0.0);
3665 /* wait for just a little while, because the above call is asynchronous */
3667 Glib::usleep (250000);
3669 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3673 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3675 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3676 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3678 d.set_title (_("Cannot freeze"));
3683 if (clicked_routeview->track()->has_external_redirects()) {
3684 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"
3685 "Freezing will only process the signal as far as the first send/insert/return."),
3686 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3688 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3689 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3690 d.set_title (_("Freeze Limits"));
3692 int response = d.run ();
3695 case Gtk::RESPONSE_CANCEL:
3702 InterThreadInfo itt;
3703 current_interthread_info = &itt;
3705 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3707 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3709 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3711 while (!itt.done && !itt.cancel) {
3712 gtk_main_iteration ();
3715 current_interthread_info = 0;
3719 Editor::bounce_range_selection (bool replace, bool enable_processing)
3721 if (selection->time.empty()) {
3725 TrackSelection views = selection->tracks;
3727 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3729 if (enable_processing) {
3731 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3733 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3735 _("You can't perform this operation because the processing of the signal "
3736 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3737 "You can do this without processing, which is a different operation.")
3739 d.set_title (_("Cannot bounce"));
3746 framepos_t start = selection->time[clicked_selection].start;
3747 framepos_t end = selection->time[clicked_selection].end;
3748 framepos_t cnt = end - start + 1;
3750 begin_reversible_command (_("bounce range"));
3752 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3754 RouteTimeAxisView* rtv;
3756 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3760 boost::shared_ptr<Playlist> playlist;
3762 if ((playlist = rtv->playlist()) == 0) {
3766 InterThreadInfo itt;
3768 playlist->clear_changes ();
3769 playlist->clear_owned_changes ();
3771 boost::shared_ptr<Region> r;
3773 if (enable_processing) {
3774 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3776 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3784 list<AudioRange> ranges;
3785 ranges.push_back (AudioRange (start, start+cnt, 0));
3786 playlist->cut (ranges); // discard result
3787 playlist->add_region (r, start);
3790 vector<Command*> cmds;
3791 playlist->rdiff (cmds);
3792 _session->add_commands (cmds);
3794 _session->add_command (new StatefulDiffCommand (playlist));
3797 commit_reversible_command ();
3800 /** Delete selected regions, automation points or a time range */
3804 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3805 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3806 bool deleted = false;
3807 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3808 deleted = current_mixer_strip->delete_processors ();
3814 /** Cut selected regions, automation points or a time range */
3821 /** Copy selected regions, automation points or a time range */
3829 /** @return true if a Cut, Copy or Clear is possible */
3831 Editor::can_cut_copy () const
3833 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3840 /** Cut, copy or clear selected regions, automation points or a time range.
3841 * @param op Operation (Delete, Cut, Copy or Clear)
3844 Editor::cut_copy (CutCopyOp op)
3846 /* only cancel selection if cut/copy is successful.*/
3852 opname = _("delete");
3861 opname = _("clear");
3865 /* if we're deleting something, and the mouse is still pressed,
3866 the thing we started a drag for will be gone when we release
3867 the mouse button(s). avoid this. see part 2 at the end of
3871 if (op == Delete || op == Cut || op == Clear) {
3872 if (_drags->active ()) {
3877 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3878 cut_buffer->clear ();
3880 if (entered_marker) {
3882 /* cut/delete op while pointing at a marker */
3885 Location* loc = find_location_from_marker (entered_marker, ignored);
3887 if (_session && loc) {
3888 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3895 switch (mouse_mode) {
3898 begin_reversible_command (opname + ' ' + X_("MIDI"));
3900 commit_reversible_command ();
3906 bool did_edit = false;
3908 if (!selection->regions.empty() || !selection->points.empty()) {
3909 begin_reversible_command (opname + ' ' + _("objects"));
3912 if (!selection->regions.empty()) {
3913 cut_copy_regions (op, selection->regions);
3915 if (op == Cut || op == Delete) {
3916 selection->clear_regions ();
3920 if (!selection->points.empty()) {
3921 cut_copy_points (op);
3923 if (op == Cut || op == Delete) {
3924 selection->clear_points ();
3927 } else if (selection->time.empty()) {
3928 framepos_t start, end;
3929 /* no time selection, see if we can get an edit range
3932 if (get_edit_op_range (start, end)) {
3933 selection->set (start, end);
3935 } else if (!selection->time.empty()) {
3936 begin_reversible_command (opname + ' ' + _("range"));
3939 cut_copy_ranges (op);
3941 if (op == Cut || op == Delete) {
3942 selection->clear_time ();
3947 /* reset repeated paste state */
3950 commit_reversible_command ();
3953 if (op == Delete || op == Cut || op == Clear) {
3958 struct AutomationRecord {
3959 AutomationRecord () : state (0) , line(NULL) {}
3960 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3962 XMLNode* state; ///< state before any operation
3963 const AutomationLine* line; ///< line this came from
3964 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3967 /** Cut, copy or clear selected automation points.
3968 * @param op Operation (Cut, Copy or Clear)
3971 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3973 if (selection->points.empty ()) {
3977 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3978 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3980 /* Keep a record of the AutomationLists that we end up using in this operation */
3981 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3984 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3985 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3986 const AutomationLine& line = (*i)->line();
3987 const boost::shared_ptr<AutomationList> al = line.the_list();
3988 if (lists.find (al) == lists.end ()) {
3989 /* We haven't seen this list yet, so make a record for it. This includes
3990 taking a copy of its current state, in case this is needed for undo later.
3992 lists[al] = AutomationRecord (&al->get_state (), &line);
3996 if (op == Cut || op == Copy) {
3997 /* This operation will involve putting things in the cut buffer, so create an empty
3998 ControlList for each of our source lists to put the cut buffer data in.
4000 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4001 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4004 /* Add all selected points to the relevant copy ControlLists */
4005 framepos_t start = std::numeric_limits<framepos_t>::max();
4006 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4007 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4008 AutomationList::const_iterator j = (*i)->model();
4010 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4012 /* Update earliest MIDI start time in beats */
4013 earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
4015 /* Update earliest session start time in frames */
4016 start = std::min(start, (*i)->line().session_position(j));
4020 /* Snap start time backwards, so copy/paste is snap aligned. */
4022 if (earliest == Evoral::MusicalTime::max()) {
4023 earliest = Evoral::MusicalTime(); // Weird... don't offset
4025 earliest.round_down_to_beat();
4027 if (start == std::numeric_limits<double>::max()) {
4028 start = 0; // Weird... don't offset
4030 snap_to(start, RoundDownMaybe);
4033 const double line_offset = midi ? earliest.to_double() : start;
4034 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4035 /* Correct this copy list so that it is relative to the earliest
4036 start time, so relative ordering between points is preserved
4037 when copying from several lists and the paste starts at the
4038 earliest copied piece of data. */
4039 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4040 (*j)->when -= line_offset;
4043 /* And add it to the cut buffer */
4044 cut_buffer->add (i->second.copy);
4048 if (op == Delete || op == Cut) {
4049 /* This operation needs to remove things from the main AutomationList, so do that now */
4051 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4052 i->first->freeze ();
4055 /* Remove each selected point from its AutomationList */
4056 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4057 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4058 al->erase ((*i)->model ());
4061 /* Thaw the lists and add undo records for them */
4062 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4063 boost::shared_ptr<AutomationList> al = i->first;
4065 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4070 /** Cut, copy or clear selected automation points.
4071 * @param op Operation (Cut, Copy or Clear)
4074 Editor::cut_copy_midi (CutCopyOp op)
4076 Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4077 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4078 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4080 if (!mrv->selection().empty()) {
4081 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4083 mrv->cut_copy_clear (op);
4085 /* XXX: not ideal, as there may be more than one track involved in the selection */
4086 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4090 if (!selection->points.empty()) {
4091 cut_copy_points (op, earliest, true);
4092 if (op == Cut || op == Delete) {
4093 selection->clear_points ();
4098 struct lt_playlist {
4099 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4100 return a.playlist < b.playlist;
4104 struct PlaylistMapping {
4106 boost::shared_ptr<Playlist> pl;
4108 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4111 /** Remove `clicked_regionview' */
4113 Editor::remove_clicked_region ()
4115 if (clicked_routeview == 0 || clicked_regionview == 0) {
4119 begin_reversible_command (_("remove region"));
4121 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4123 playlist->clear_changes ();
4124 playlist->clear_owned_changes ();
4125 playlist->remove_region (clicked_regionview->region());
4126 if (Config->get_edit_mode() == Ripple)
4127 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4129 /* We might have removed regions, which alters other regions' layering_index,
4130 so we need to do a recursive diff here.
4132 vector<Command*> cmds;
4133 playlist->rdiff (cmds);
4134 _session->add_commands (cmds);
4136 _session->add_command(new StatefulDiffCommand (playlist));
4137 commit_reversible_command ();
4141 /** Remove the selected regions */
4143 Editor::remove_selected_regions ()
4145 RegionSelection rs = get_regions_from_selection_and_entered ();
4147 if (!_session || rs.empty()) {
4151 begin_reversible_command (_("remove region"));
4153 list<boost::shared_ptr<Region> > regions_to_remove;
4155 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4156 // we can't just remove the region(s) in this loop because
4157 // this removes them from the RegionSelection, and they thus
4158 // disappear from underneath the iterator, and the ++i above
4159 // SEGVs in a puzzling fashion.
4161 // so, first iterate over the regions to be removed from rs and
4162 // add them to the regions_to_remove list, and then
4163 // iterate over the list to actually remove them.
4165 regions_to_remove.push_back ((*i)->region());
4168 vector<boost::shared_ptr<Playlist> > playlists;
4170 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4172 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4175 // is this check necessary?
4179 /* get_regions_from_selection_and_entered() guarantees that
4180 the playlists involved are unique, so there is no need
4184 playlists.push_back (playlist);
4186 playlist->clear_changes ();
4187 playlist->clear_owned_changes ();
4188 playlist->freeze ();
4189 playlist->remove_region (*rl);
4190 if (Config->get_edit_mode() == Ripple)
4191 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4195 vector<boost::shared_ptr<Playlist> >::iterator pl;
4197 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4200 /* We might have removed regions, which alters other regions' layering_index,
4201 so we need to do a recursive diff here.
4203 vector<Command*> cmds;
4204 (*pl)->rdiff (cmds);
4205 _session->add_commands (cmds);
4207 _session->add_command(new StatefulDiffCommand (*pl));
4210 commit_reversible_command ();
4213 /** Cut, copy or clear selected regions.
4214 * @param op Operation (Cut, Copy or Clear)
4217 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4219 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4220 a map when we want ordered access to both elements. i think.
4223 vector<PlaylistMapping> pmap;
4225 framepos_t first_position = max_framepos;
4227 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4228 FreezeList freezelist;
4230 /* get ordering correct before we cut/copy */
4232 rs.sort_by_position_and_track ();
4234 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4236 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4238 if (op == Cut || op == Clear || op == Delete) {
4239 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4242 FreezeList::iterator fl;
4244 // only take state if this is a new playlist.
4245 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4251 if (fl == freezelist.end()) {
4252 pl->clear_changes();
4253 pl->clear_owned_changes ();
4255 freezelist.insert (pl);
4260 TimeAxisView* tv = &(*x)->get_time_axis_view();
4261 vector<PlaylistMapping>::iterator z;
4263 for (z = pmap.begin(); z != pmap.end(); ++z) {
4264 if ((*z).tv == tv) {
4269 if (z == pmap.end()) {
4270 pmap.push_back (PlaylistMapping (tv));
4274 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4276 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4279 /* region not yet associated with a playlist (e.g. unfinished
4286 TimeAxisView& tv = (*x)->get_time_axis_view();
4287 boost::shared_ptr<Playlist> npl;
4288 RegionSelection::iterator tmp;
4295 vector<PlaylistMapping>::iterator z;
4297 for (z = pmap.begin(); z != pmap.end(); ++z) {
4298 if ((*z).tv == &tv) {
4303 assert (z != pmap.end());
4306 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4314 boost::shared_ptr<Region> r = (*x)->region();
4315 boost::shared_ptr<Region> _xx;
4321 pl->remove_region (r);
4322 if (Config->get_edit_mode() == Ripple)
4323 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4327 _xx = RegionFactory::create (r);
4328 npl->add_region (_xx, r->position() - first_position);
4329 pl->remove_region (r);
4330 if (Config->get_edit_mode() == Ripple)
4331 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4335 /* copy region before adding, so we're not putting same object into two different playlists */
4336 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4340 pl->remove_region (r);
4341 if (Config->get_edit_mode() == Ripple)
4342 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4351 list<boost::shared_ptr<Playlist> > foo;
4353 /* the pmap is in the same order as the tracks in which selected regions occured */
4355 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4358 foo.push_back ((*i).pl);
4363 cut_buffer->set (foo);
4367 _last_cut_copy_source_track = 0;
4369 _last_cut_copy_source_track = pmap.front().tv;
4373 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4376 /* We might have removed regions, which alters other regions' layering_index,
4377 so we need to do a recursive diff here.
4379 vector<Command*> cmds;
4380 (*pl)->rdiff (cmds);
4381 _session->add_commands (cmds);
4383 _session->add_command (new StatefulDiffCommand (*pl));
4388 Editor::cut_copy_ranges (CutCopyOp op)
4390 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4392 /* Sort the track selection now, so that it if is used, the playlists
4393 selected by the calls below to cut_copy_clear are in the order that
4394 their tracks appear in the editor. This makes things like paste
4395 of ranges work properly.
4398 sort_track_selection (ts);
4401 if (!entered_track) {
4404 ts.push_back (entered_track);
4407 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4408 (*i)->cut_copy_clear (*selection, op);
4413 Editor::paste (float times, bool from_context)
4415 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4417 paste_internal (get_preferred_edit_position (false, from_context), times);
4421 Editor::mouse_paste ()
4426 if (!mouse_frame (where, ignored)) {
4431 paste_internal (where, 1);
4435 Editor::paste_internal (framepos_t position, float times)
4437 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4439 if (cut_buffer->empty(internal_editing())) {
4443 if (position == max_framepos) {
4444 position = get_preferred_edit_position();
4445 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4448 if (position == last_paste_pos) {
4449 /* repeated paste in the same position */
4452 /* paste in new location, reset repeated paste state */
4454 last_paste_pos = position;
4457 /* get everything in the correct order */
4460 if (!selection->tracks.empty()) {
4461 /* If there is a track selection, paste into exactly those tracks and
4462 only those tracks. This allows the user to be explicit and override
4463 the below "do the reasonable thing" logic. */
4464 ts = selection->tracks.filter_to_unique_playlists ();
4465 sort_track_selection (ts);
4467 /* Figure out which track to base the paste at. */
4468 TimeAxisView* base_track = NULL;
4469 if (_edit_point == Editing::EditAtMouse && entered_track) {
4470 /* With the mouse edit point, paste onto the track under the mouse. */
4471 base_track = entered_track;
4472 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4473 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4474 base_track = &entered_regionview->get_time_axis_view();
4475 } else if (_last_cut_copy_source_track) {
4476 /* Paste to the track that the cut/copy came from (see mantis #333). */
4477 base_track = _last_cut_copy_source_track;
4479 /* This is "impossible" since we've copied... well, do nothing. */
4483 /* Walk up to parent if necessary, so base track is a route. */
4484 while (base_track->get_parent()) {
4485 base_track = base_track->get_parent();
4488 /* Add base track and all tracks below it. The paste logic will select
4489 the appropriate object types from the cut buffer in relative order. */
4490 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4491 if ((*i)->order() >= base_track->order()) {
4496 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4497 sort_track_selection (ts);
4499 /* Add automation children of each track in order, for pasting several lines. */
4500 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4501 /* Add any automation children for pasting several lines */
4502 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4507 typedef RouteTimeAxisView::AutomationTracks ATracks;
4508 const ATracks& atracks = rtv->automation_tracks();
4509 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4510 i = ts.insert(i, a->second.get());
4515 /* We now have a list of trackviews starting at base_track, including
4516 automation children, in the order shown in the editor, e.g. R1,
4517 R1.A1, R1.A2, R2, R2.A1, ... */
4520 begin_reversible_command (Operations::paste);
4522 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4523 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4524 /* Only one line copied, and one automation track selected. Do a
4525 "greedy" paste from one automation type to another. */
4527 PasteContext ctx(paste_count, times, ItemCounts(), true);
4528 ts.front()->paste (position, *cut_buffer, ctx);
4532 /* Paste into tracks */
4534 PasteContext ctx(paste_count, times, ItemCounts(), false);
4535 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4536 (*i)->paste (position, *cut_buffer, ctx);
4540 commit_reversible_command ();
4544 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4546 boost::shared_ptr<Playlist> playlist;
4547 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4548 RegionSelection foo;
4550 framepos_t const start_frame = regions.start ();
4551 framepos_t const end_frame = regions.end_frame ();
4553 begin_reversible_command (Operations::duplicate_region);
4555 selection->clear_regions ();
4557 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4559 boost::shared_ptr<Region> r ((*i)->region());
4561 TimeAxisView& tv = (*i)->get_time_axis_view();
4562 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4563 latest_regionviews.clear ();
4564 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4566 playlist = (*i)->region()->playlist();
4567 playlist->clear_changes ();
4568 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4569 _session->add_command(new StatefulDiffCommand (playlist));
4573 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4577 selection->set (foo);
4580 commit_reversible_command ();
4584 Editor::duplicate_selection (float times)
4586 if (selection->time.empty() || selection->tracks.empty()) {
4590 boost::shared_ptr<Playlist> playlist;
4591 vector<boost::shared_ptr<Region> > new_regions;
4592 vector<boost::shared_ptr<Region> >::iterator ri;
4594 create_region_from_selection (new_regions);
4596 if (new_regions.empty()) {
4600 begin_reversible_command (_("duplicate selection"));
4602 ri = new_regions.begin();
4604 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4606 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4607 if ((playlist = (*i)->playlist()) == 0) {
4610 playlist->clear_changes ();
4612 if (clicked_selection) {
4613 end = selection->time[clicked_selection].end;
4615 end = selection->time.end_frame();
4617 playlist->duplicate (*ri, end, times);
4618 _session->add_command (new StatefulDiffCommand (playlist));
4621 if (ri == new_regions.end()) {
4626 commit_reversible_command ();
4629 /** Reset all selected points to the relevant default value */
4631 Editor::reset_point_selection ()
4633 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4634 ARDOUR::AutomationList::iterator j = (*i)->model ();
4635 (*j)->value = (*i)->line().the_list()->default_value ();
4640 Editor::center_playhead ()
4642 float const page = _visible_canvas_width * samples_per_pixel;
4643 center_screen_internal (playhead_cursor->current_frame (), page);
4647 Editor::center_edit_point ()
4649 float const page = _visible_canvas_width * samples_per_pixel;
4650 center_screen_internal (get_preferred_edit_position(), page);
4653 /** Caller must begin and commit a reversible command */
4655 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4657 playlist->clear_changes ();
4659 _session->add_command (new StatefulDiffCommand (playlist));
4663 Editor::nudge_track (bool use_edit, bool forwards)
4665 boost::shared_ptr<Playlist> playlist;
4666 framepos_t distance;
4667 framepos_t next_distance;
4671 start = get_preferred_edit_position();
4676 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4680 if (selection->tracks.empty()) {
4684 begin_reversible_command (_("nudge track"));
4686 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4688 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4690 if ((playlist = (*i)->playlist()) == 0) {
4694 playlist->clear_changes ();
4695 playlist->clear_owned_changes ();
4697 playlist->nudge_after (start, distance, forwards);
4699 vector<Command*> cmds;
4701 playlist->rdiff (cmds);
4702 _session->add_commands (cmds);
4704 _session->add_command (new StatefulDiffCommand (playlist));
4707 commit_reversible_command ();
4711 Editor::remove_last_capture ()
4713 vector<string> choices;
4720 if (Config->get_verify_remove_last_capture()) {
4721 prompt = _("Do you really want to destroy the last capture?"
4722 "\n(This is destructive and cannot be undone)");
4724 choices.push_back (_("No, do nothing."));
4725 choices.push_back (_("Yes, destroy it."));
4727 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4729 if (prompter.run () == 1) {
4730 _session->remove_last_capture ();
4731 _regions->redisplay ();
4735 _session->remove_last_capture();
4736 _regions->redisplay ();
4741 Editor::normalize_region ()
4747 RegionSelection rs = get_regions_from_selection_and_entered ();
4753 NormalizeDialog dialog (rs.size() > 1);
4755 if (dialog.run () == RESPONSE_CANCEL) {
4759 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4762 /* XXX: should really only count audio regions here */
4763 int const regions = rs.size ();
4765 /* Make a list of the selected audio regions' maximum amplitudes, and also
4766 obtain the maximum amplitude of them all.
4768 list<double> max_amps;
4770 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4771 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4773 dialog.descend (1.0 / regions);
4774 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4777 /* the user cancelled the operation */
4781 max_amps.push_back (a);
4782 max_amp = max (max_amp, a);
4787 begin_reversible_command (_("normalize"));
4789 list<double>::const_iterator a = max_amps.begin ();
4791 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4792 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4797 arv->region()->clear_changes ();
4799 double const amp = dialog.normalize_individually() ? *a : max_amp;
4801 arv->audio_region()->normalize (amp, dialog.target ());
4802 _session->add_command (new StatefulDiffCommand (arv->region()));
4807 commit_reversible_command ();
4812 Editor::reset_region_scale_amplitude ()
4818 RegionSelection rs = get_regions_from_selection_and_entered ();
4824 begin_reversible_command ("reset gain");
4826 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4827 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4830 arv->region()->clear_changes ();
4831 arv->audio_region()->set_scale_amplitude (1.0f);
4832 _session->add_command (new StatefulDiffCommand (arv->region()));
4835 commit_reversible_command ();
4839 Editor::adjust_region_gain (bool up)
4841 RegionSelection rs = get_regions_from_selection_and_entered ();
4843 if (!_session || rs.empty()) {
4847 begin_reversible_command ("adjust region gain");
4849 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4850 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4855 arv->region()->clear_changes ();
4857 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4865 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4866 _session->add_command (new StatefulDiffCommand (arv->region()));
4869 commit_reversible_command ();
4874 Editor::reverse_region ()
4880 Reverse rev (*_session);
4881 apply_filter (rev, _("reverse regions"));
4885 Editor::strip_region_silence ()
4891 RegionSelection rs = get_regions_from_selection_and_entered ();
4897 std::list<RegionView*> audio_only;
4899 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4900 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4902 audio_only.push_back (arv);
4906 StripSilenceDialog d (_session, audio_only);
4907 int const r = d.run ();
4911 if (r == Gtk::RESPONSE_OK) {
4912 ARDOUR::AudioIntervalMap silences;
4913 d.silences (silences);
4914 StripSilence s (*_session, silences, d.fade_length());
4915 apply_filter (s, _("strip silence"), &d);
4920 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4922 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4923 mrv.selection_as_notelist (selected, true);
4925 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4926 v.push_back (selected);
4928 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4929 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4931 return op (mrv.midi_region()->model(), pos_beats, v);
4935 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
4941 begin_reversible_command (op.name ());
4943 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
4944 RegionSelection::const_iterator tmp = r;
4947 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4950 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4953 _session->add_command (cmd);
4960 commit_reversible_command ();
4964 Editor::fork_region ()
4966 RegionSelection rs = get_regions_from_selection_and_entered ();
4972 begin_reversible_command (_("Fork Region(s)"));
4974 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4977 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4978 RegionSelection::iterator tmp = r;
4981 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4985 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4986 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4987 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4989 playlist->clear_changes ();
4990 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4991 _session->add_command(new StatefulDiffCommand (playlist));
4993 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5000 commit_reversible_command ();
5004 Editor::quantize_region ()
5007 quantize_regions(get_regions_from_selection_and_entered ());
5012 Editor::quantize_regions (const RegionSelection& rs)
5014 if (rs.n_midi_regions() == 0) {
5018 QuantizeDialog* qd = new QuantizeDialog (*this);
5021 const int r = qd->run ();
5024 if (r == Gtk::RESPONSE_OK) {
5025 Quantize quant (qd->snap_start(), qd->snap_end(),
5026 qd->start_grid_size(), qd->end_grid_size(),
5027 qd->strength(), qd->swing(), qd->threshold());
5029 apply_midi_note_edit_op (quant, rs);
5034 Editor::legatize_region (bool shrink_only)
5037 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5042 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5044 if (rs.n_midi_regions() == 0) {
5048 Legatize legatize(shrink_only);
5049 apply_midi_note_edit_op (legatize, rs);
5053 Editor::transform_region ()
5056 transform_regions(get_regions_from_selection_and_entered ());
5061 Editor::transform_regions (const RegionSelection& rs)
5063 if (rs.n_midi_regions() == 0) {
5067 TransformDialog* td = new TransformDialog();
5070 const int r = td->run();
5073 if (r == Gtk::RESPONSE_OK) {
5074 Transform transform(td->get());
5075 apply_midi_note_edit_op(transform, rs);
5080 Editor::insert_patch_change (bool from_context)
5082 RegionSelection rs = get_regions_from_selection_and_entered ();
5088 const framepos_t p = get_preferred_edit_position (false, from_context);
5090 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5091 there may be more than one, but the PatchChangeDialog can only offer
5092 one set of patch menus.
5094 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5096 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5097 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5099 if (d.run() == RESPONSE_CANCEL) {
5103 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5104 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5106 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5107 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5114 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5116 RegionSelection rs = get_regions_from_selection_and_entered ();
5122 begin_reversible_command (command);
5124 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5128 int const N = rs.size ();
5130 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5131 RegionSelection::iterator tmp = r;
5134 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5136 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5139 progress->descend (1.0 / N);
5142 if (arv->audio_region()->apply (filter, progress) == 0) {
5144 playlist->clear_changes ();
5145 playlist->clear_owned_changes ();
5147 if (filter.results.empty ()) {
5149 /* no regions returned; remove the old one */
5150 playlist->remove_region (arv->region ());
5154 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5156 /* first region replaces the old one */
5157 playlist->replace_region (arv->region(), *res, (*res)->position());
5161 while (res != filter.results.end()) {
5162 playlist->add_region (*res, (*res)->position());
5168 /* We might have removed regions, which alters other regions' layering_index,
5169 so we need to do a recursive diff here.
5171 vector<Command*> cmds;
5172 playlist->rdiff (cmds);
5173 _session->add_commands (cmds);
5175 _session->add_command(new StatefulDiffCommand (playlist));
5181 progress->ascend ();
5189 commit_reversible_command ();
5193 Editor::external_edit_region ()
5199 Editor::reset_region_gain_envelopes ()
5201 RegionSelection rs = get_regions_from_selection_and_entered ();
5203 if (!_session || rs.empty()) {
5207 begin_reversible_command (_("reset region gain"));
5209 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5210 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5212 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5213 XMLNode& before (alist->get_state());
5215 arv->audio_region()->set_default_envelope ();
5216 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5220 commit_reversible_command ();
5224 Editor::set_region_gain_visibility (RegionView* rv)
5226 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5228 arv->update_envelope_visibility();
5233 Editor::set_gain_envelope_visibility ()
5239 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5240 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5242 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5248 Editor::toggle_gain_envelope_active ()
5250 if (_ignore_region_action) {
5254 RegionSelection rs = get_regions_from_selection_and_entered ();
5256 if (!_session || rs.empty()) {
5260 begin_reversible_command (_("region gain envelope active"));
5262 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5263 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5265 arv->region()->clear_changes ();
5266 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5267 _session->add_command (new StatefulDiffCommand (arv->region()));
5271 commit_reversible_command ();
5275 Editor::toggle_region_lock ()
5277 if (_ignore_region_action) {
5281 RegionSelection rs = get_regions_from_selection_and_entered ();
5283 if (!_session || rs.empty()) {
5287 begin_reversible_command (_("toggle region lock"));
5289 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5290 (*i)->region()->clear_changes ();
5291 (*i)->region()->set_locked (!(*i)->region()->locked());
5292 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5295 commit_reversible_command ();
5299 Editor::toggle_region_video_lock ()
5301 if (_ignore_region_action) {
5305 RegionSelection rs = get_regions_from_selection_and_entered ();
5307 if (!_session || rs.empty()) {
5311 begin_reversible_command (_("Toggle Video Lock"));
5313 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5314 (*i)->region()->clear_changes ();
5315 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5316 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5319 commit_reversible_command ();
5323 Editor::toggle_region_lock_style ()
5325 if (_ignore_region_action) {
5329 RegionSelection rs = get_regions_from_selection_and_entered ();
5331 if (!_session || rs.empty()) {
5335 begin_reversible_command (_("region lock style"));
5337 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5338 (*i)->region()->clear_changes ();
5339 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5340 (*i)->region()->set_position_lock_style (ns);
5341 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5344 commit_reversible_command ();
5348 Editor::toggle_opaque_region ()
5350 if (_ignore_region_action) {
5354 RegionSelection rs = get_regions_from_selection_and_entered ();
5356 if (!_session || rs.empty()) {
5360 begin_reversible_command (_("change region opacity"));
5362 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5363 (*i)->region()->clear_changes ();
5364 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5365 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5368 commit_reversible_command ();
5372 Editor::toggle_record_enable ()
5374 bool new_state = false;
5376 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5377 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5380 if (!rtav->is_track())
5384 new_state = !rtav->track()->record_enabled();
5388 rtav->track()->set_record_enabled (new_state, this);
5393 Editor::toggle_solo ()
5395 bool new_state = false;
5397 boost::shared_ptr<RouteList> rl (new RouteList);
5399 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5400 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5407 new_state = !rtav->route()->soloed ();
5411 rl->push_back (rtav->route());
5414 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5418 Editor::toggle_mute ()
5420 bool new_state = false;
5422 boost::shared_ptr<RouteList> rl (new RouteList);
5424 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5425 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5432 new_state = !rtav->route()->muted();
5436 rl->push_back (rtav->route());
5439 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5443 Editor::toggle_solo_isolate ()
5449 Editor::fade_range ()
5451 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5453 begin_reversible_command (_("fade range"));
5455 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5456 (*i)->fade_range (selection->time);
5459 commit_reversible_command ();
5464 Editor::set_fade_length (bool in)
5466 RegionSelection rs = get_regions_from_selection_and_entered ();
5472 /* we need a region to measure the offset from the start */
5474 RegionView* rv = rs.front ();
5476 framepos_t pos = get_preferred_edit_position();
5480 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5481 /* edit point is outside the relevant region */
5486 if (pos <= rv->region()->position()) {
5490 len = pos - rv->region()->position();
5491 cmd = _("set fade in length");
5493 if (pos >= rv->region()->last_frame()) {
5497 len = rv->region()->last_frame() - pos;
5498 cmd = _("set fade out length");
5501 begin_reversible_command (cmd);
5503 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5504 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5510 boost::shared_ptr<AutomationList> alist;
5512 alist = tmp->audio_region()->fade_in();
5514 alist = tmp->audio_region()->fade_out();
5517 XMLNode &before = alist->get_state();
5520 tmp->audio_region()->set_fade_in_length (len);
5521 tmp->audio_region()->set_fade_in_active (true);
5523 tmp->audio_region()->set_fade_out_length (len);
5524 tmp->audio_region()->set_fade_out_active (true);
5527 XMLNode &after = alist->get_state();
5528 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5531 commit_reversible_command ();
5535 Editor::set_fade_in_shape (FadeShape shape)
5537 RegionSelection rs = get_regions_from_selection_and_entered ();
5543 begin_reversible_command (_("set fade in shape"));
5545 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5546 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5552 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5553 XMLNode &before = alist->get_state();
5555 tmp->audio_region()->set_fade_in_shape (shape);
5557 XMLNode &after = alist->get_state();
5558 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5561 commit_reversible_command ();
5566 Editor::set_fade_out_shape (FadeShape shape)
5568 RegionSelection rs = get_regions_from_selection_and_entered ();
5574 begin_reversible_command (_("set fade out shape"));
5576 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5577 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5583 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5584 XMLNode &before = alist->get_state();
5586 tmp->audio_region()->set_fade_out_shape (shape);
5588 XMLNode &after = alist->get_state();
5589 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5592 commit_reversible_command ();
5596 Editor::set_fade_in_active (bool yn)
5598 RegionSelection rs = get_regions_from_selection_and_entered ();
5604 begin_reversible_command (_("set fade in active"));
5606 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5607 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5614 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5616 ar->clear_changes ();
5617 ar->set_fade_in_active (yn);
5618 _session->add_command (new StatefulDiffCommand (ar));
5621 commit_reversible_command ();
5625 Editor::set_fade_out_active (bool yn)
5627 RegionSelection rs = get_regions_from_selection_and_entered ();
5633 begin_reversible_command (_("set fade out active"));
5635 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5636 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5642 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5644 ar->clear_changes ();
5645 ar->set_fade_out_active (yn);
5646 _session->add_command(new StatefulDiffCommand (ar));
5649 commit_reversible_command ();
5653 Editor::toggle_region_fades (int dir)
5655 if (_ignore_region_action) {
5659 boost::shared_ptr<AudioRegion> ar;
5662 RegionSelection rs = get_regions_from_selection_and_entered ();
5668 RegionSelection::iterator i;
5669 for (i = rs.begin(); i != rs.end(); ++i) {
5670 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5672 yn = ar->fade_out_active ();
5674 yn = ar->fade_in_active ();
5680 if (i == rs.end()) {
5684 /* XXX should this undo-able? */
5686 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5687 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5690 if (dir == 1 || dir == 0) {
5691 ar->set_fade_in_active (!yn);
5694 if (dir == -1 || dir == 0) {
5695 ar->set_fade_out_active (!yn);
5701 /** Update region fade visibility after its configuration has been changed */
5703 Editor::update_region_fade_visibility ()
5705 bool _fade_visibility = _session->config.get_show_region_fades ();
5707 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5708 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5710 if (_fade_visibility) {
5711 v->audio_view()->show_all_fades ();
5713 v->audio_view()->hide_all_fades ();
5720 Editor::set_edit_point ()
5725 if (!mouse_frame (where, ignored)) {
5731 if (selection->markers.empty()) {
5733 mouse_add_new_marker (where);
5738 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5741 loc->move_to (where);
5747 Editor::set_playhead_cursor ()
5749 if (entered_marker) {
5750 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5755 if (!mouse_frame (where, ignored)) {
5762 _session->request_locate (where, _session->transport_rolling());
5766 if (ARDOUR_UI::config()->get_follow_edits()) {
5767 cancel_time_selection();
5772 Editor::split_region ()
5774 if ( !selection->time.empty()) {
5775 separate_regions_between (selection->time);
5779 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5781 framepos_t where = get_preferred_edit_position ();
5787 split_regions_at (where, rs);
5790 struct EditorOrderRouteSorter {
5791 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5792 return a->order_key () < b->order_key ();
5797 Editor::select_next_route()
5799 if (selection->tracks.empty()) {
5800 selection->set (track_views.front());
5804 TimeAxisView* current = selection->tracks.front();
5808 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5809 if (*i == current) {
5811 if (i != track_views.end()) {
5814 current = (*(track_views.begin()));
5815 //selection->set (*(track_views.begin()));
5820 rui = dynamic_cast<RouteUI *>(current);
5821 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5823 selection->set(current);
5825 ensure_time_axis_view_is_visible (*current, false);
5829 Editor::select_prev_route()
5831 if (selection->tracks.empty()) {
5832 selection->set (track_views.front());
5836 TimeAxisView* current = selection->tracks.front();
5840 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5841 if (*i == current) {
5843 if (i != track_views.rend()) {
5846 current = *(track_views.rbegin());
5851 rui = dynamic_cast<RouteUI *>(current);
5852 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5854 selection->set (current);
5856 ensure_time_axis_view_is_visible (*current, false);
5860 Editor::set_loop_from_selection (bool play)
5862 if (_session == 0 || selection->time.empty()) {
5866 framepos_t start = selection->time[clicked_selection].start;
5867 framepos_t end = selection->time[clicked_selection].end;
5869 set_loop_range (start, end, _("set loop range from selection"));
5872 _session->request_locate (start, true);
5873 _session->request_play_loop (true);
5878 Editor::set_loop_from_edit_range (bool play)
5880 if (_session == 0) {
5887 if (!get_edit_op_range (start, end)) {
5891 set_loop_range (start, end, _("set loop range from edit range"));
5894 _session->request_locate (start, true);
5895 _session->request_play_loop (true);
5900 Editor::set_loop_from_region (bool play)
5902 framepos_t start = max_framepos;
5905 RegionSelection rs = get_regions_from_selection_and_entered ();
5911 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5912 if ((*i)->region()->position() < start) {
5913 start = (*i)->region()->position();
5915 if ((*i)->region()->last_frame() + 1 > end) {
5916 end = (*i)->region()->last_frame() + 1;
5920 set_loop_range (start, end, _("set loop range from region"));
5923 _session->request_locate (start, true);
5924 _session->request_play_loop (true);
5929 Editor::set_punch_from_selection ()
5931 if (_session == 0 || selection->time.empty()) {
5935 framepos_t start = selection->time[clicked_selection].start;
5936 framepos_t end = selection->time[clicked_selection].end;
5938 set_punch_range (start, end, _("set punch range from selection"));
5942 Editor::set_session_extents_from_selection ()
5944 if (_session == 0 || selection->time.empty()) {
5948 begin_reversible_command (_("set session start/stop from selection"));
5950 framepos_t start = selection->time[clicked_selection].start;
5951 framepos_t end = selection->time[clicked_selection].end;
5954 if ((loc = _session->locations()->session_range_location()) == 0) {
5955 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5957 XMLNode &before = loc->get_state();
5959 _session->set_session_extents ( start, end );
5961 XMLNode &after = loc->get_state();
5963 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5965 commit_reversible_command ();
5970 Editor::set_punch_from_edit_range ()
5972 if (_session == 0) {
5979 if (!get_edit_op_range (start, end)) {
5983 set_punch_range (start, end, _("set punch range from edit range"));
5987 Editor::set_punch_from_region ()
5989 framepos_t start = max_framepos;
5992 RegionSelection rs = get_regions_from_selection_and_entered ();
5998 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5999 if ((*i)->region()->position() < start) {
6000 start = (*i)->region()->position();
6002 if ((*i)->region()->last_frame() + 1 > end) {
6003 end = (*i)->region()->last_frame() + 1;
6007 set_punch_range (start, end, _("set punch range from region"));
6011 Editor::pitch_shift_region ()
6013 RegionSelection rs = get_regions_from_selection_and_entered ();
6015 RegionSelection audio_rs;
6016 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6017 if (dynamic_cast<AudioRegionView*> (*i)) {
6018 audio_rs.push_back (*i);
6022 if (audio_rs.empty()) {
6026 pitch_shift (audio_rs, 1.2);
6030 Editor::transpose_region ()
6032 RegionSelection rs = get_regions_from_selection_and_entered ();
6034 list<MidiRegionView*> midi_region_views;
6035 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6036 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6038 midi_region_views.push_back (mrv);
6043 int const r = d.run ();
6044 if (r != RESPONSE_ACCEPT) {
6048 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6049 (*i)->midi_region()->transpose (d.semitones ());
6054 Editor::set_tempo_from_region ()
6056 RegionSelection rs = get_regions_from_selection_and_entered ();
6058 if (!_session || rs.empty()) {
6062 RegionView* rv = rs.front();
6064 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6068 Editor::use_range_as_bar ()
6070 framepos_t start, end;
6071 if (get_edit_op_range (start, end)) {
6072 define_one_bar (start, end);
6077 Editor::define_one_bar (framepos_t start, framepos_t end)
6079 framepos_t length = end - start;
6081 const Meter& m (_session->tempo_map().meter_at (start));
6083 /* length = 1 bar */
6085 /* now we want frames per beat.
6086 we have frames per bar, and beats per bar, so ...
6089 /* XXXX METER MATH */
6091 double frames_per_beat = length / m.divisions_per_bar();
6093 /* beats per minute = */
6095 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6097 /* now decide whether to:
6099 (a) set global tempo
6100 (b) add a new tempo marker
6104 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6106 bool do_global = false;
6108 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6110 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6111 at the start, or create a new marker
6114 vector<string> options;
6115 options.push_back (_("Cancel"));
6116 options.push_back (_("Add new marker"));
6117 options.push_back (_("Set global tempo"));
6120 _("Define one bar"),
6121 _("Do you want to set the global tempo or add a new tempo marker?"),
6125 c.set_default_response (2);
6141 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6142 if the marker is at the region starter, change it, otherwise add
6147 begin_reversible_command (_("set tempo from region"));
6148 XMLNode& before (_session->tempo_map().get_state());
6151 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6152 } else if (t.frame() == start) {
6153 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6155 Timecode::BBT_Time bbt;
6156 _session->tempo_map().bbt_time (start, bbt);
6157 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6160 XMLNode& after (_session->tempo_map().get_state());
6162 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6163 commit_reversible_command ();
6167 Editor::split_region_at_transients ()
6169 AnalysisFeatureList positions;
6171 RegionSelection rs = get_regions_from_selection_and_entered ();
6173 if (!_session || rs.empty()) {
6177 begin_reversible_command (_("split regions"));
6179 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6181 RegionSelection::iterator tmp;
6186 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6188 if (ar && (ar->get_transients (positions) == 0)) {
6189 split_region_at_points ((*i)->region(), positions, true);
6196 commit_reversible_command ();
6201 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6203 bool use_rhythmic_rodent = false;
6205 boost::shared_ptr<Playlist> pl = r->playlist();
6207 list<boost::shared_ptr<Region> > new_regions;
6213 if (positions.empty()) {
6218 if (positions.size() > 20 && can_ferret) {
6219 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);
6220 MessageDialog msg (msgstr,
6223 Gtk::BUTTONS_OK_CANCEL);
6226 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6227 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6229 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6232 msg.set_title (_("Excessive split?"));
6235 int response = msg.run();
6241 case RESPONSE_APPLY:
6242 use_rhythmic_rodent = true;
6249 if (use_rhythmic_rodent) {
6250 show_rhythm_ferret ();
6254 AnalysisFeatureList::const_iterator x;
6256 pl->clear_changes ();
6257 pl->clear_owned_changes ();
6259 x = positions.begin();
6261 if (x == positions.end()) {
6266 pl->remove_region (r);
6270 while (x != positions.end()) {
6272 /* deal with positons that are out of scope of present region bounds */
6273 if (*x <= 0 || *x > r->length()) {
6278 /* file start = original start + how far we from the initial position ?
6281 framepos_t file_start = r->start() + pos;
6283 /* length = next position - current position
6286 framepos_t len = (*x) - pos;
6288 /* XXX we do we really want to allow even single-sample regions?
6289 shouldn't we have some kind of lower limit on region size?
6298 if (RegionFactory::region_name (new_name, r->name())) {
6302 /* do NOT announce new regions 1 by one, just wait till they are all done */
6306 plist.add (ARDOUR::Properties::start, file_start);
6307 plist.add (ARDOUR::Properties::length, len);
6308 plist.add (ARDOUR::Properties::name, new_name);
6309 plist.add (ARDOUR::Properties::layer, 0);
6311 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6312 /* because we set annouce to false, manually add the new region to the
6315 RegionFactory::map_add (nr);
6317 pl->add_region (nr, r->position() + pos);
6320 new_regions.push_front(nr);
6329 RegionFactory::region_name (new_name, r->name());
6331 /* Add the final region */
6334 plist.add (ARDOUR::Properties::start, r->start() + pos);
6335 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6336 plist.add (ARDOUR::Properties::name, new_name);
6337 plist.add (ARDOUR::Properties::layer, 0);
6339 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6340 /* because we set annouce to false, manually add the new region to the
6343 RegionFactory::map_add (nr);
6344 pl->add_region (nr, r->position() + pos);
6347 new_regions.push_front(nr);
6352 /* We might have removed regions, which alters other regions' layering_index,
6353 so we need to do a recursive diff here.
6355 vector<Command*> cmds;
6357 _session->add_commands (cmds);
6359 _session->add_command (new StatefulDiffCommand (pl));
6363 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6364 set_selected_regionview_from_region_list ((*i), Selection::Add);
6370 Editor::place_transient()
6376 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6382 framepos_t where = get_preferred_edit_position();
6384 begin_reversible_command (_("place transient"));
6386 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6387 framepos_t position = (*r)->region()->position();
6388 (*r)->region()->add_transient(where - position);
6391 commit_reversible_command ();
6395 Editor::remove_transient(ArdourCanvas::Item* item)
6401 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6404 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6405 _arv->remove_transient (*(float*) _line->get_data ("position"));
6409 Editor::snap_regions_to_grid ()
6411 list <boost::shared_ptr<Playlist > > used_playlists;
6413 RegionSelection rs = get_regions_from_selection_and_entered ();
6415 if (!_session || rs.empty()) {
6419 begin_reversible_command (_("snap regions to grid"));
6421 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6423 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6425 if (!pl->frozen()) {
6426 /* we haven't seen this playlist before */
6428 /* remember used playlists so we can thaw them later */
6429 used_playlists.push_back(pl);
6433 framepos_t start_frame = (*r)->region()->first_frame ();
6434 snap_to (start_frame);
6435 (*r)->region()->set_position (start_frame);
6438 while (used_playlists.size() > 0) {
6439 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6441 used_playlists.pop_front();
6444 commit_reversible_command ();
6448 Editor::close_region_gaps ()
6450 list <boost::shared_ptr<Playlist > > used_playlists;
6452 RegionSelection rs = get_regions_from_selection_and_entered ();
6454 if (!_session || rs.empty()) {
6458 Dialog dialog (_("Close Region Gaps"));
6461 table.set_spacings (12);
6462 table.set_border_width (12);
6463 Label* l = manage (left_aligned_label (_("Crossfade length")));
6464 table.attach (*l, 0, 1, 0, 1);
6466 SpinButton spin_crossfade (1, 0);
6467 spin_crossfade.set_range (0, 15);
6468 spin_crossfade.set_increments (1, 1);
6469 spin_crossfade.set_value (5);
6470 table.attach (spin_crossfade, 1, 2, 0, 1);
6472 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6474 l = manage (left_aligned_label (_("Pull-back length")));
6475 table.attach (*l, 0, 1, 1, 2);
6477 SpinButton spin_pullback (1, 0);
6478 spin_pullback.set_range (0, 100);
6479 spin_pullback.set_increments (1, 1);
6480 spin_pullback.set_value(30);
6481 table.attach (spin_pullback, 1, 2, 1, 2);
6483 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6485 dialog.get_vbox()->pack_start (table);
6486 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6487 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6490 if (dialog.run () == RESPONSE_CANCEL) {
6494 framepos_t crossfade_len = spin_crossfade.get_value();
6495 framepos_t pull_back_frames = spin_pullback.get_value();
6497 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6498 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6500 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6502 begin_reversible_command (_("close region gaps"));
6505 boost::shared_ptr<Region> last_region;
6507 rs.sort_by_position_and_track();
6509 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6511 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6513 if (!pl->frozen()) {
6514 /* we haven't seen this playlist before */
6516 /* remember used playlists so we can thaw them later */
6517 used_playlists.push_back(pl);
6521 framepos_t position = (*r)->region()->position();
6523 if (idx == 0 || position < last_region->position()){
6524 last_region = (*r)->region();
6529 (*r)->region()->trim_front( (position - pull_back_frames));
6530 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6532 last_region = (*r)->region();
6537 while (used_playlists.size() > 0) {
6538 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6540 used_playlists.pop_front();
6543 commit_reversible_command ();
6547 Editor::tab_to_transient (bool forward)
6549 AnalysisFeatureList positions;
6551 RegionSelection rs = get_regions_from_selection_and_entered ();
6557 framepos_t pos = _session->audible_frame ();
6559 if (!selection->tracks.empty()) {
6561 /* don't waste time searching for transients in duplicate playlists.
6564 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6566 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6568 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6571 boost::shared_ptr<Track> tr = rtv->track();
6573 boost::shared_ptr<Playlist> pl = tr->playlist ();
6575 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6578 positions.push_back (result);
6591 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6592 (*r)->region()->get_transients (positions);
6596 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6599 AnalysisFeatureList::iterator x;
6601 for (x = positions.begin(); x != positions.end(); ++x) {
6607 if (x != positions.end ()) {
6608 _session->request_locate (*x);
6612 AnalysisFeatureList::reverse_iterator x;
6614 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6620 if (x != positions.rend ()) {
6621 _session->request_locate (*x);
6627 Editor::playhead_forward_to_grid ()
6633 framepos_t pos = playhead_cursor->current_frame ();
6634 if (pos < max_framepos - 1) {
6636 snap_to_internal (pos, RoundUpAlways, false);
6637 _session->request_locate (pos);
6643 Editor::playhead_backward_to_grid ()
6649 framepos_t pos = playhead_cursor->current_frame ();
6652 snap_to_internal (pos, RoundDownAlways, false);
6653 _session->request_locate (pos);
6658 Editor::set_track_height (Height h)
6660 TrackSelection& ts (selection->tracks);
6662 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6663 (*x)->set_height_enum (h);
6668 Editor::toggle_tracks_active ()
6670 TrackSelection& ts (selection->tracks);
6672 bool target = false;
6678 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6679 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6683 target = !rtv->_route->active();
6686 rtv->_route->set_active (target, this);
6692 Editor::remove_tracks ()
6694 TrackSelection& ts (selection->tracks);
6700 vector<string> choices;
6704 const char* trackstr;
6706 vector<boost::shared_ptr<Route> > routes;
6707 bool special_bus = false;
6709 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6710 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6714 if (rtv->is_track()) {
6719 routes.push_back (rtv->_route);
6721 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6726 if (special_bus && !Config->get_allow_special_bus_removal()) {
6727 MessageDialog msg (_("That would be bad news ...."),
6731 msg.set_secondary_text (string_compose (_(
6732 "Removing the master or monitor bus is such a bad idea\n\
6733 that %1 is not going to allow it.\n\
6735 If you really want to do this sort of thing\n\
6736 edit your ardour.rc file to set the\n\
6737 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6744 if (ntracks + nbusses == 0) {
6748 // XXX should be using gettext plural forms, maybe?
6750 trackstr = _("tracks");
6752 trackstr = _("track");
6756 busstr = _("busses");
6763 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6764 "(You may also lose the playlists associated with the %2)\n\n"
6765 "This action cannot be undone, and the session file will be overwritten!"),
6766 ntracks, trackstr, nbusses, busstr);
6768 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6769 "(You may also lose the playlists associated with the %2)\n\n"
6770 "This action cannot be undone, and the session file will be overwritten!"),
6773 } else if (nbusses) {
6774 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6775 "This action cannot be undone, and the session file will be overwritten"),
6779 choices.push_back (_("No, do nothing."));
6780 if (ntracks + nbusses > 1) {
6781 choices.push_back (_("Yes, remove them."));
6783 choices.push_back (_("Yes, remove it."));
6788 title = string_compose (_("Remove %1"), trackstr);
6790 title = string_compose (_("Remove %1"), busstr);
6793 Choice prompter (title, prompt, choices);
6795 if (prompter.run () != 1) {
6800 Session::StateProtector sp (_session);
6801 DisplaySuspender ds;
6802 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6803 _session->remove_route (*x);
6809 Editor::do_insert_time ()
6811 if (selection->tracks.empty()) {
6815 InsertTimeDialog d (*this);
6816 int response = d.run ();
6818 if (response != RESPONSE_OK) {
6822 if (d.distance() == 0) {
6826 InsertTimeOption opt = d.intersected_region_action ();
6829 get_preferred_edit_position(),
6835 d.move_glued_markers(),
6836 d.move_locked_markers(),
6842 Editor::insert_time (
6843 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6844 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6847 bool commit = false;
6849 if (Config->get_edit_mode() == Lock) {
6853 begin_reversible_command (_("insert time"));
6855 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6857 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6861 /* don't operate on any playlist more than once, which could
6862 * happen if "all playlists" is enabled, but there is more
6863 * than 1 track using playlists "from" a given track.
6866 set<boost::shared_ptr<Playlist> > pl;
6868 if (all_playlists) {
6869 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6871 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6872 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6877 if ((*x)->playlist ()) {
6878 pl.insert ((*x)->playlist ());
6882 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6884 (*i)->clear_changes ();
6885 (*i)->clear_owned_changes ();
6887 if (opt == SplitIntersected) {
6891 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6893 vector<Command*> cmds;
6895 _session->add_commands (cmds);
6897 _session->add_command (new StatefulDiffCommand (*i));
6902 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6904 rtav->route ()->shift (pos, frames);
6912 XMLNode& before (_session->locations()->get_state());
6913 Locations::LocationList copy (_session->locations()->list());
6915 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6917 Locations::LocationList::const_iterator tmp;
6919 bool const was_locked = (*i)->locked ();
6920 if (locked_markers_too) {
6924 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6926 if ((*i)->start() >= pos) {
6927 (*i)->set_start ((*i)->start() + frames);
6928 if (!(*i)->is_mark()) {
6929 (*i)->set_end ((*i)->end() + frames);
6942 XMLNode& after (_session->locations()->get_state());
6943 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6948 _session->tempo_map().insert_time (pos, frames);
6952 commit_reversible_command ();
6957 Editor::fit_selected_tracks ()
6959 if (!selection->tracks.empty()) {
6960 fit_tracks (selection->tracks);
6964 /* no selected tracks - use tracks with selected regions */
6966 if (!selection->regions.empty()) {
6967 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6968 tvl.push_back (&(*r)->get_time_axis_view ());
6974 } else if (internal_editing()) {
6975 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6978 if (entered_track) {
6979 tvl.push_back (entered_track);
6988 Editor::fit_tracks (TrackViewList & tracks)
6990 if (tracks.empty()) {
6994 uint32_t child_heights = 0;
6995 int visible_tracks = 0;
6997 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6999 if (!(*t)->marked_for_display()) {
7003 child_heights += (*t)->effective_height() - (*t)->current_height();
7007 /* compute the per-track height from:
7009 total canvas visible height -
7010 height that will be taken by visible children of selected
7011 tracks - height of the ruler/hscroll area
7013 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7014 double first_y_pos = DBL_MAX;
7016 if (h < TimeAxisView::preset_height (HeightSmall)) {
7017 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7018 /* too small to be displayed */
7022 undo_visual_stack.push_back (current_visual_state (true));
7023 no_save_visual = true;
7025 /* build a list of all tracks, including children */
7028 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7030 TimeAxisView::Children c = (*i)->get_child_list ();
7031 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7032 all.push_back (j->get());
7036 bool prev_was_selected = false;
7037 bool is_selected = tracks.contains (all.front());
7038 bool next_is_selected;
7040 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7042 TrackViewList::iterator next;
7047 if (next != all.end()) {
7048 next_is_selected = tracks.contains (*next);
7050 next_is_selected = false;
7053 if ((*t)->marked_for_display ()) {
7055 (*t)->set_height (h);
7056 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7058 if (prev_was_selected && next_is_selected) {
7059 hide_track_in_display (*t);
7064 prev_was_selected = is_selected;
7065 is_selected = next_is_selected;
7069 set the controls_layout height now, because waiting for its size
7070 request signal handler will cause the vertical adjustment setting to fail
7073 controls_layout.property_height () = _full_canvas_height;
7074 vertical_adjustment.set_value (first_y_pos);
7076 redo_visual_stack.push_back (current_visual_state (true));
7078 visible_tracks_selector.set_text (_("Sel"));
7082 Editor::save_visual_state (uint32_t n)
7084 while (visual_states.size() <= n) {
7085 visual_states.push_back (0);
7088 if (visual_states[n] != 0) {
7089 delete visual_states[n];
7092 visual_states[n] = current_visual_state (true);
7097 Editor::goto_visual_state (uint32_t n)
7099 if (visual_states.size() <= n) {
7103 if (visual_states[n] == 0) {
7107 use_visual_state (*visual_states[n]);
7111 Editor::start_visual_state_op (uint32_t n)
7113 save_visual_state (n);
7115 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7117 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7118 pup->set_text (buf);
7123 Editor::cancel_visual_state_op (uint32_t n)
7125 goto_visual_state (n);
7129 Editor::toggle_region_mute ()
7131 if (_ignore_region_action) {
7135 RegionSelection rs = get_regions_from_selection_and_entered ();
7141 if (rs.size() > 1) {
7142 begin_reversible_command (_("mute regions"));
7144 begin_reversible_command (_("mute region"));
7147 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7149 (*i)->region()->playlist()->clear_changes ();
7150 (*i)->region()->set_muted (!(*i)->region()->muted ());
7151 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7155 commit_reversible_command ();
7159 Editor::combine_regions ()
7161 /* foreach track with selected regions, take all selected regions
7162 and join them into a new region containing the subregions (as a
7166 typedef set<RouteTimeAxisView*> RTVS;
7169 if (selection->regions.empty()) {
7173 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7174 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7177 tracks.insert (rtv);
7181 begin_reversible_command (_("combine regions"));
7183 vector<RegionView*> new_selection;
7185 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7188 if ((rv = (*i)->combine_regions ()) != 0) {
7189 new_selection.push_back (rv);
7193 selection->clear_regions ();
7194 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7195 selection->add (*i);
7198 commit_reversible_command ();
7202 Editor::uncombine_regions ()
7204 typedef set<RouteTimeAxisView*> RTVS;
7207 if (selection->regions.empty()) {
7211 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7212 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7215 tracks.insert (rtv);
7219 begin_reversible_command (_("uncombine regions"));
7221 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7222 (*i)->uncombine_regions ();
7225 commit_reversible_command ();
7229 Editor::toggle_midi_input_active (bool flip_others)
7232 boost::shared_ptr<RouteList> rl (new RouteList);
7234 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7235 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7241 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7244 rl->push_back (rtav->route());
7245 onoff = !mt->input_active();
7249 _session->set_exclusive_input_active (rl, onoff, flip_others);
7256 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7258 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7259 lock_dialog->get_vbox()->pack_start (*padlock);
7261 ArdourButton* b = manage (new ArdourButton);
7262 b->set_name ("lock button");
7263 b->set_text (_("Click to unlock"));
7264 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7265 lock_dialog->get_vbox()->pack_start (*b);
7267 lock_dialog->get_vbox()->show_all ();
7268 lock_dialog->set_size_request (200, 200);
7272 /* The global menu bar continues to be accessible to applications
7273 with modal dialogs, which means that we need to desensitize
7274 all items in the menu bar. Since those items are really just
7275 proxies for actions, that means disabling all actions.
7277 ActionManager::disable_all_actions ();
7279 lock_dialog->present ();
7285 lock_dialog->hide ();
7288 ActionManager::pop_action_state ();
7291 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7292 start_lock_event_timing ();
7297 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7299 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7303 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7305 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7306 Gtkmm2ext::UI::instance()->flush_pending ();
7310 Editor::bring_all_sources_into_session ()
7317 ArdourDialog w (_("Moving embedded files into session folder"));
7318 w.get_vbox()->pack_start (msg);
7321 /* flush all pending GUI events because we're about to start copying
7325 Gtkmm2ext::UI::instance()->flush_pending ();
7329 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));