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 */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/operations.h"
48 #include "ardour/playlist_factory.h"
49 #include "ardour/quantize.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/reverse.h"
52 #include "ardour/session.h"
53 #include "ardour/session_playlists.h"
54 #include "ardour/strip_silence.h"
55 #include "ardour/transient_detector.h"
57 #include "ardour_ui.h"
60 #include "time_axis_view.h"
61 #include "route_time_axis.h"
62 #include "audio_time_axis.h"
63 #include "automation_time_axis.h"
64 #include "control_point.h"
65 #include "streamview.h"
66 #include "audio_streamview.h"
67 #include "audio_region_view.h"
68 #include "midi_region_view.h"
69 #include "rgb_macros.h"
70 #include "selection_templates.h"
71 #include "selection.h"
73 #include "gtk-custom-hruler.h"
74 #include "gui_thread.h"
77 #include "editor_drag.h"
78 #include "strip_silence_dialog.h"
79 #include "editor_routes.h"
80 #include "editor_regions.h"
81 #include "quantize_dialog.h"
82 #include "interthread_progress_window.h"
83 #include "insert_time_dialog.h"
84 #include "normalize_dialog.h"
85 #include "editor_cursors.h"
86 #include "mouse_cursors.h"
87 #include "patch_change_dialog.h"
88 #include "transpose_dialog.h"
93 using namespace ARDOUR;
96 using namespace Gtkmm2ext;
97 using namespace Editing;
98 using Gtkmm2ext::Keyboard;
100 /***********************************************************************
102 ***********************************************************************/
105 Editor::undo (uint32_t n)
107 if (_drags->active ()) {
117 Editor::redo (uint32_t n)
119 if (_drags->active ()) {
129 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
133 list <boost::shared_ptr<Playlist > > used_playlists;
135 if (regions.empty()) {
139 begin_reversible_command (_("split"));
141 // if splitting a single region, and snap-to is using
142 // region boundaries, don't pay attention to them
144 if (regions.size() == 1) {
145 switch (_snap_type) {
146 case SnapToRegionStart:
147 case SnapToRegionSync:
148 case SnapToRegionEnd:
157 EditorFreeze(); /* Emit Signal */
160 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
162 RegionSelection::iterator tmp;
164 /* XXX this test needs to be more complicated, to make sure we really
165 have something to split.
168 if (!(*a)->region()->covers (where)) {
176 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
184 /* we haven't seen this playlist before */
186 /* remember used playlists so we can thaw them later */
187 used_playlists.push_back(pl);
192 pl->clear_changes ();
193 pl->split_region ((*a)->region(), where);
194 _session->add_command (new StatefulDiffCommand (pl));
200 while (used_playlists.size() > 0) {
201 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
203 used_playlists.pop_front();
206 commit_reversible_command ();
209 EditorThaw(); /* Emit Signal */
213 /** Move one extreme of the current range selection. If more than one range is selected,
214 * the start of the earliest range or the end of the latest range is moved.
216 * @param move_end true to move the end of the current range selection, false to move
218 * @param next true to move the extreme to the next region boundary, false to move to
222 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
224 if (selection->time.start() == selection->time.end_frame()) {
228 framepos_t start = selection->time.start ();
229 framepos_t end = selection->time.end_frame ();
231 /* the position of the thing we may move */
232 framepos_t pos = move_end ? end : start;
233 int dir = next ? 1 : -1;
235 /* so we don't find the current region again */
236 if (dir > 0 || pos > 0) {
240 framepos_t const target = get_region_boundary (pos, dir, true, false);
255 begin_reversible_command (_("alter selection"));
256 selection->set_preserving_all_ranges (start, end);
257 commit_reversible_command ();
261 Editor::nudge_forward_release (GdkEventButton* ev)
263 if (ev->state & Keyboard::PrimaryModifier) {
264 nudge_forward (false, true);
266 nudge_forward (false, false);
272 Editor::nudge_backward_release (GdkEventButton* ev)
274 if (ev->state & Keyboard::PrimaryModifier) {
275 nudge_backward (false, true);
277 nudge_backward (false, false);
284 Editor::nudge_forward (bool next, bool force_playhead)
287 framepos_t next_distance;
293 RegionSelection rs = get_regions_from_selection_and_entered ();
295 if (!force_playhead && !rs.empty()) {
297 begin_reversible_command (_("nudge regions forward"));
299 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
300 boost::shared_ptr<Region> r ((*i)->region());
302 distance = get_nudge_distance (r->position(), next_distance);
305 distance = next_distance;
309 r->set_position (r->position() + distance);
310 _session->add_command (new StatefulDiffCommand (r));
313 commit_reversible_command ();
316 } else if (!force_playhead && !selection->markers.empty()) {
320 begin_reversible_command (_("nudge location forward"));
322 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
324 Location* loc = find_location_from_marker ((*i), is_start);
328 XMLNode& before (loc->get_state());
331 distance = get_nudge_distance (loc->start(), next_distance);
333 distance = next_distance;
335 if (max_framepos - distance > loc->start() + loc->length()) {
336 loc->set_start (loc->start() + distance);
338 loc->set_start (max_framepos - loc->length());
341 distance = get_nudge_distance (loc->end(), next_distance);
343 distance = next_distance;
345 if (max_framepos - distance > loc->end()) {
346 loc->set_end (loc->end() + distance);
348 loc->set_end (max_framepos);
351 XMLNode& after (loc->get_state());
352 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
356 commit_reversible_command ();
359 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
360 _session->request_locate (playhead_cursor->current_frame + distance);
365 Editor::nudge_backward (bool next, bool force_playhead)
368 framepos_t next_distance;
374 RegionSelection rs = get_regions_from_selection_and_entered ();
376 if (!force_playhead && !rs.empty()) {
378 begin_reversible_command (_("nudge regions backward"));
380 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
381 boost::shared_ptr<Region> r ((*i)->region());
383 distance = get_nudge_distance (r->position(), next_distance);
386 distance = next_distance;
391 if (r->position() > distance) {
392 r->set_position (r->position() - distance);
396 _session->add_command (new StatefulDiffCommand (r));
399 commit_reversible_command ();
401 } else if (!force_playhead && !selection->markers.empty()) {
405 begin_reversible_command (_("nudge location forward"));
407 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
409 Location* loc = find_location_from_marker ((*i), is_start);
413 XMLNode& before (loc->get_state());
416 distance = get_nudge_distance (loc->start(), next_distance);
418 distance = next_distance;
420 if (distance < loc->start()) {
421 loc->set_start (loc->start() - distance);
426 distance = get_nudge_distance (loc->end(), next_distance);
429 distance = next_distance;
432 if (distance < loc->end() - loc->length()) {
433 loc->set_end (loc->end() - distance);
435 loc->set_end (loc->length());
439 XMLNode& after (loc->get_state());
440 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
444 commit_reversible_command ();
448 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
450 if (playhead_cursor->current_frame > distance) {
451 _session->request_locate (playhead_cursor->current_frame - distance);
453 _session->goto_start();
459 Editor::nudge_forward_capture_offset ()
461 RegionSelection rs = get_regions_from_selection_and_entered ();
463 if (!_session || rs.empty()) {
467 begin_reversible_command (_("nudge forward"));
469 framepos_t const distance = _session->worst_output_latency();
471 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
472 boost::shared_ptr<Region> r ((*i)->region());
475 r->set_position (r->position() + distance);
476 _session->add_command(new StatefulDiffCommand (r));
479 commit_reversible_command ();
483 Editor::nudge_backward_capture_offset ()
485 RegionSelection rs = get_regions_from_selection_and_entered ();
487 if (!_session || rs.empty()) {
491 begin_reversible_command (_("nudge backward"));
493 framepos_t const distance = _session->worst_output_latency();
495 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
496 boost::shared_ptr<Region> r ((*i)->region());
500 if (r->position() > distance) {
501 r->set_position (r->position() - distance);
505 _session->add_command(new StatefulDiffCommand (r));
508 commit_reversible_command ();
514 Editor::move_to_start ()
516 _session->goto_start ();
520 Editor::move_to_end ()
523 _session->request_locate (_session->current_end_frame());
527 Editor::build_region_boundary_cache ()
530 vector<RegionPoint> interesting_points;
531 boost::shared_ptr<Region> r;
532 TrackViewList tracks;
535 region_boundary_cache.clear ();
541 switch (_snap_type) {
542 case SnapToRegionStart:
543 interesting_points.push_back (Start);
545 case SnapToRegionEnd:
546 interesting_points.push_back (End);
548 case SnapToRegionSync:
549 interesting_points.push_back (SyncPoint);
551 case SnapToRegionBoundary:
552 interesting_points.push_back (Start);
553 interesting_points.push_back (End);
556 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
561 TimeAxisView *ontrack = 0;
564 if (!selection->tracks.empty()) {
565 tlist = selection->tracks.filter_to_unique_playlists ();
567 tlist = track_views.filter_to_unique_playlists ();
570 while (pos < _session->current_end_frame() && !at_end) {
573 framepos_t lpos = max_framepos;
575 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
577 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
578 if (*p == interesting_points.back()) {
581 /* move to next point type */
587 rpos = r->first_frame();
591 rpos = r->last_frame();
595 rpos = r->sync_position ();
603 RouteTimeAxisView *rtav;
605 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
606 if (rtav->track() != 0) {
607 speed = rtav->track()->speed();
611 rpos = track_frame_to_session_frame (rpos, speed);
617 /* prevent duplicates, but we don't use set<> because we want to be able
621 vector<framepos_t>::iterator ri;
623 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
629 if (ri == region_boundary_cache.end()) {
630 region_boundary_cache.push_back (rpos);
637 /* finally sort to be sure that the order is correct */
639 sort (region_boundary_cache.begin(), region_boundary_cache.end());
642 boost::shared_ptr<Region>
643 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
645 TrackViewList::iterator i;
646 framepos_t closest = max_framepos;
647 boost::shared_ptr<Region> ret;
651 framepos_t track_frame;
652 RouteTimeAxisView *rtav;
654 for (i = tracks.begin(); i != tracks.end(); ++i) {
657 boost::shared_ptr<Region> r;
660 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
661 if (rtav->track()!=0)
662 track_speed = rtav->track()->speed();
665 track_frame = session_frame_to_track_frame(frame, track_speed);
667 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
673 rpos = r->first_frame ();
677 rpos = r->last_frame ();
681 rpos = r->sync_position ();
685 // rpos is a "track frame", converting it to "_session frame"
686 rpos = track_frame_to_session_frame(rpos, track_speed);
689 distance = rpos - frame;
691 distance = frame - rpos;
694 if (distance < closest) {
706 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
708 framecnt_t distance = max_framepos;
709 framepos_t current_nearest = -1;
711 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
712 framepos_t contender;
715 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
721 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
725 d = ::llabs (pos - contender);
728 current_nearest = contender;
733 return current_nearest;
737 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
742 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
744 if (!selection->tracks.empty()) {
746 target = find_next_region_boundary (pos, dir, selection->tracks);
750 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
751 get_onscreen_tracks (tvl);
752 target = find_next_region_boundary (pos, dir, tvl);
754 target = find_next_region_boundary (pos, dir, track_views);
760 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
761 get_onscreen_tracks (tvl);
762 target = find_next_region_boundary (pos, dir, tvl);
764 target = find_next_region_boundary (pos, dir, track_views);
772 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
774 framepos_t pos = playhead_cursor->current_frame;
781 // so we don't find the current region again..
782 if (dir > 0 || pos > 0) {
786 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
790 _session->request_locate (target);
794 Editor::cursor_to_next_region_boundary (bool with_selection)
796 cursor_to_region_boundary (with_selection, 1);
800 Editor::cursor_to_previous_region_boundary (bool with_selection)
802 cursor_to_region_boundary (with_selection, -1);
806 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
808 boost::shared_ptr<Region> r;
809 framepos_t pos = cursor->current_frame;
815 TimeAxisView *ontrack = 0;
817 // so we don't find the current region again..
821 if (!selection->tracks.empty()) {
823 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
825 } else if (clicked_axisview) {
828 t.push_back (clicked_axisview);
830 r = find_next_region (pos, point, dir, t, &ontrack);
834 r = find_next_region (pos, point, dir, track_views, &ontrack);
843 pos = r->first_frame ();
847 pos = r->last_frame ();
851 pos = r->sync_position ();
856 RouteTimeAxisView *rtav;
858 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
859 if (rtav->track() != 0) {
860 speed = rtav->track()->speed();
864 pos = track_frame_to_session_frame(pos, speed);
866 if (cursor == playhead_cursor) {
867 _session->request_locate (pos);
869 cursor->set_position (pos);
874 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
876 cursor_to_region_point (cursor, point, 1);
880 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
882 cursor_to_region_point (cursor, point, -1);
886 Editor::cursor_to_selection_start (EditorCursor *cursor)
890 switch (mouse_mode) {
892 if (!selection->regions.empty()) {
893 pos = selection->regions.start();
898 if (!selection->time.empty()) {
899 pos = selection->time.start ();
907 if (cursor == playhead_cursor) {
908 _session->request_locate (pos);
910 cursor->set_position (pos);
915 Editor::cursor_to_selection_end (EditorCursor *cursor)
919 switch (mouse_mode) {
921 if (!selection->regions.empty()) {
922 pos = selection->regions.end_frame();
927 if (!selection->time.empty()) {
928 pos = selection->time.end_frame ();
936 if (cursor == playhead_cursor) {
937 _session->request_locate (pos);
939 cursor->set_position (pos);
944 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
954 if (selection->markers.empty()) {
958 if (!mouse_frame (mouse, ignored)) {
962 add_location_mark (mouse);
965 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
969 framepos_t pos = loc->start();
971 // so we don't find the current region again..
972 if (dir > 0 || pos > 0) {
976 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
980 loc->move_to (target);
984 Editor::selected_marker_to_next_region_boundary (bool with_selection)
986 selected_marker_to_region_boundary (with_selection, 1);
990 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
992 selected_marker_to_region_boundary (with_selection, -1);
996 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
998 boost::shared_ptr<Region> r;
1003 if (!_session || selection->markers.empty()) {
1007 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1011 TimeAxisView *ontrack = 0;
1015 // so we don't find the current region again..
1019 if (!selection->tracks.empty()) {
1021 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1025 r = find_next_region (pos, point, dir, track_views, &ontrack);
1034 pos = r->first_frame ();
1038 pos = r->last_frame ();
1042 pos = r->adjust_to_sync (r->first_frame());
1047 RouteTimeAxisView *rtav;
1049 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1050 if (rtav->track() != 0) {
1051 speed = rtav->track()->speed();
1055 pos = track_frame_to_session_frame(pos, speed);
1061 Editor::selected_marker_to_next_region_point (RegionPoint point)
1063 selected_marker_to_region_point (point, 1);
1067 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1069 selected_marker_to_region_point (point, -1);
1073 Editor::selected_marker_to_selection_start ()
1079 if (!_session || selection->markers.empty()) {
1083 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1087 switch (mouse_mode) {
1089 if (!selection->regions.empty()) {
1090 pos = selection->regions.start();
1095 if (!selection->time.empty()) {
1096 pos = selection->time.start ();
1108 Editor::selected_marker_to_selection_end ()
1114 if (!_session || selection->markers.empty()) {
1118 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1122 switch (mouse_mode) {
1124 if (!selection->regions.empty()) {
1125 pos = selection->regions.end_frame();
1130 if (!selection->time.empty()) {
1131 pos = selection->time.end_frame ();
1143 Editor::scroll_playhead (bool forward)
1145 framepos_t pos = playhead_cursor->current_frame;
1146 framecnt_t delta = (framecnt_t) floor (current_page_frames() / 0.8);
1149 if (pos == max_framepos) {
1153 if (pos < max_framepos - delta) {
1172 _session->request_locate (pos);
1176 Editor::cursor_align (bool playhead_to_edit)
1182 if (playhead_to_edit) {
1184 if (selection->markers.empty()) {
1188 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1191 /* move selected markers to playhead */
1193 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1196 Location* loc = find_location_from_marker (*i, ignored);
1198 if (loc->is_mark()) {
1199 loc->set_start (playhead_cursor->current_frame);
1201 loc->set (playhead_cursor->current_frame,
1202 playhead_cursor->current_frame + loc->length());
1209 Editor::scroll_backward (float pages)
1211 framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1212 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1215 if (leftmost_frame < cnt) {
1218 frame = leftmost_frame - cnt;
1221 reset_x_origin (frame);
1225 Editor::scroll_forward (float pages)
1227 framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1228 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1231 if (max_framepos - cnt < leftmost_frame) {
1232 frame = max_framepos - cnt;
1234 frame = leftmost_frame + cnt;
1237 reset_x_origin (frame);
1241 Editor::scroll_tracks_down ()
1243 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1244 if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1245 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1248 vertical_adjustment.set_value (vert_value);
1252 Editor::scroll_tracks_up ()
1254 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1258 Editor::scroll_tracks_down_line ()
1260 double vert_value = vertical_adjustment.get_value() + 60;
1262 if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1263 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1266 vertical_adjustment.set_value (vert_value);
1270 Editor::scroll_tracks_up_line ()
1272 reset_y_origin (vertical_adjustment.get_value() - 60);
1278 Editor::tav_zoom_step (bool coarser)
1280 _routes->suspend_redisplay ();
1284 if (selection->tracks.empty()) {
1287 ts = &selection->tracks;
1290 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1291 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1292 tv->step_height (coarser);
1295 _routes->resume_redisplay ();
1299 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1301 _routes->suspend_redisplay ();
1305 if (selection->tracks.empty() || force_all) {
1308 ts = &selection->tracks;
1311 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1312 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1313 uint32_t h = tv->current_height ();
1318 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1323 tv->set_height (h + 5);
1327 _routes->resume_redisplay ();
1331 Editor::clamp_frames_per_unit (double& fpu) const
1333 bool clamped = false;
1340 if (max_framepos / fpu < 800) {
1341 fpu = max_framepos / 800.0;
1349 Editor::temporal_zoom_step (bool coarser)
1351 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1353 double nfpu = frames_per_unit;
1356 nfpu = min (9e6, nfpu * 1.61803399);
1358 nfpu = max (1.0, nfpu / 1.61803399);
1361 temporal_zoom (nfpu);
1365 Editor::temporal_zoom (double fpu)
1371 framepos_t current_page = current_page_frames();
1372 framepos_t current_leftmost = leftmost_frame;
1373 framepos_t current_rightmost;
1374 framepos_t current_center;
1375 framepos_t new_page_size;
1376 framepos_t half_page_size;
1377 framepos_t leftmost_after_zoom = 0;
1379 bool in_track_canvas;
1383 clamp_frames_per_unit (fpu);
1384 if (fpu == frames_per_unit) {
1390 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1391 // segfaults for lack of memory. If somebody decides this is not high enough I
1392 // believe it can be raisen to higher values but some limit must be in place.
1397 new_page_size = (framepos_t) floor (_canvas_width * nfpu);
1398 half_page_size = new_page_size / 2;
1400 switch (zoom_focus) {
1402 leftmost_after_zoom = current_leftmost;
1405 case ZoomFocusRight:
1406 current_rightmost = leftmost_frame + current_page;
1407 if (current_rightmost < new_page_size) {
1408 leftmost_after_zoom = 0;
1410 leftmost_after_zoom = current_rightmost - new_page_size;
1414 case ZoomFocusCenter:
1415 current_center = current_leftmost + (current_page/2);
1416 if (current_center < half_page_size) {
1417 leftmost_after_zoom = 0;
1419 leftmost_after_zoom = current_center - half_page_size;
1423 case ZoomFocusPlayhead:
1424 /* centre playhead */
1425 l = playhead_cursor->current_frame - (new_page_size * 0.5);
1428 leftmost_after_zoom = 0;
1429 } else if (l > max_framepos) {
1430 leftmost_after_zoom = max_framepos - new_page_size;
1432 leftmost_after_zoom = (framepos_t) l;
1436 case ZoomFocusMouse:
1437 /* try to keep the mouse over the same point in the display */
1439 if (!mouse_frame (where, in_track_canvas)) {
1440 /* use playhead instead */
1441 where = playhead_cursor->current_frame;
1443 if (where < half_page_size) {
1444 leftmost_after_zoom = 0;
1446 leftmost_after_zoom = where - half_page_size;
1451 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1454 leftmost_after_zoom = 0;
1455 } else if (l > max_framepos) {
1456 leftmost_after_zoom = max_framepos - new_page_size;
1458 leftmost_after_zoom = (framepos_t) l;
1465 /* try to keep the edit point in the same place */
1466 where = get_preferred_edit_position ();
1470 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1473 leftmost_after_zoom = 0;
1474 } else if (l > max_framepos) {
1475 leftmost_after_zoom = max_framepos - new_page_size;
1477 leftmost_after_zoom = (framepos_t) l;
1481 /* edit point not defined */
1488 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1490 reposition_and_zoom (leftmost_after_zoom, nfpu);
1494 Editor::temporal_zoom_region (bool both_axes)
1496 framepos_t start = max_framepos;
1498 set<TimeAxisView*> tracks;
1500 RegionSelection rs = get_regions_from_selection_and_entered ();
1506 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1508 if ((*i)->region()->position() < start) {
1509 start = (*i)->region()->position();
1512 if ((*i)->region()->last_frame() + 1 > end) {
1513 end = (*i)->region()->last_frame() + 1;
1516 tracks.insert (&((*i)->get_time_axis_view()));
1519 /* now comes an "interesting" hack ... make sure we leave a little space
1520 at each end of the editor so that the zoom doesn't fit the region
1521 precisely to the screen.
1524 GdkScreen* screen = gdk_screen_get_default ();
1525 gint pixwidth = gdk_screen_get_width (screen);
1526 gint mmwidth = gdk_screen_get_width_mm (screen);
1527 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1528 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1530 if ((start == 0 && end == 0) || end < start) {
1534 framepos_t range = end - start;
1535 double new_fpu = (double)range / (double)_canvas_width;
1536 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpu);
1538 if (start > extra_samples) {
1539 start -= extra_samples;
1544 if (max_framepos - extra_samples > end) {
1545 end += extra_samples;
1550 /* if we're zooming on both axes we need to save track heights etc.
1553 undo_visual_stack.push_back (current_visual_state (both_axes));
1555 PBD::Unwinder<bool> nsv (no_save_visual, true);
1557 temporal_zoom_by_frame (start, end);
1560 uint32_t per_track_height = (uint32_t) floor ((_canvas_height - canvas_timebars_vsize - 10.0) / tracks.size());
1562 /* set visible track heights appropriately */
1564 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1565 (*t)->set_height (per_track_height);
1568 /* hide irrelevant tracks */
1570 _routes->suspend_redisplay ();
1572 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1573 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1574 hide_track_in_display (*i);
1578 _routes->resume_redisplay ();
1580 vertical_adjustment.set_value (0.0);
1583 redo_visual_stack.push_back (current_visual_state (both_axes));
1587 Editor::zoom_to_region (bool both_axes)
1589 temporal_zoom_region (both_axes);
1593 Editor::temporal_zoom_selection ()
1595 if (!selection) return;
1597 if (selection->time.empty()) {
1601 framepos_t start = selection->time[clicked_selection].start;
1602 framepos_t end = selection->time[clicked_selection].end;
1604 temporal_zoom_by_frame (start, end);
1608 Editor::temporal_zoom_session ()
1610 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1613 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1614 double s = _session->current_start_frame() - l * 0.01;
1618 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1619 temporal_zoom_by_frame (framecnt_t (s), e);
1624 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1626 if (!_session) return;
1628 if ((start == 0 && end == 0) || end < start) {
1632 framepos_t range = end - start;
1634 double new_fpu = (double)range / (double)_canvas_width;
1636 framepos_t new_page = (framepos_t) floor (_canvas_width * new_fpu);
1637 framepos_t middle = (framepos_t) floor( (double)start + ((double)range / 2.0f ));
1638 framepos_t new_leftmost = (framepos_t) floor( (double)middle - ((double)new_page/2.0f));
1640 if (new_leftmost > middle) {
1644 if (new_leftmost < 0) {
1648 reposition_and_zoom (new_leftmost, new_fpu);
1652 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1657 double range_before = frame - leftmost_frame;
1660 new_fpu = frames_per_unit;
1663 new_fpu *= 1.61803399;
1664 range_before *= 1.61803399;
1666 new_fpu = max(1.0,(new_fpu/1.61803399));
1667 range_before /= 1.61803399;
1670 if (new_fpu == frames_per_unit) {
1674 framepos_t new_leftmost = frame - (framepos_t)range_before;
1676 if (new_leftmost > frame) {
1680 if (new_leftmost < 0) {
1684 reposition_and_zoom (new_leftmost, new_fpu);
1689 Editor::choose_new_marker_name(string &name) {
1691 if (!Config->get_name_new_markers()) {
1692 /* don't prompt user for a new name */
1696 ArdourPrompter dialog (true);
1698 dialog.set_prompt (_("New Name:"));
1700 dialog.set_title (_("New Location Marker"));
1702 dialog.set_name ("MarkNameWindow");
1703 dialog.set_size_request (250, -1);
1704 dialog.set_position (Gtk::WIN_POS_MOUSE);
1706 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1707 dialog.set_initial_text (name);
1711 switch (dialog.run ()) {
1712 case RESPONSE_ACCEPT:
1718 dialog.get_result(name);
1725 Editor::add_location_from_selection ()
1729 if (selection->time.empty()) {
1733 if (_session == 0 || clicked_axisview == 0) {
1737 framepos_t start = selection->time[clicked_selection].start;
1738 framepos_t end = selection->time[clicked_selection].end;
1740 _session->locations()->next_available_name(rangename,"selection");
1741 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1743 _session->begin_reversible_command (_("add marker"));
1744 XMLNode &before = _session->locations()->get_state();
1745 _session->locations()->add (location, true);
1746 XMLNode &after = _session->locations()->get_state();
1747 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1748 _session->commit_reversible_command ();
1752 Editor::add_location_mark (framepos_t where)
1756 select_new_marker = true;
1758 _session->locations()->next_available_name(markername,"mark");
1759 if (!choose_new_marker_name(markername)) {
1762 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1763 _session->begin_reversible_command (_("add marker"));
1764 XMLNode &before = _session->locations()->get_state();
1765 _session->locations()->add (location, true);
1766 XMLNode &after = _session->locations()->get_state();
1767 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1768 _session->commit_reversible_command ();
1772 Editor::add_location_from_playhead_cursor ()
1774 add_location_mark (_session->audible_frame());
1777 /** Add a range marker around each selected region */
1779 Editor::add_locations_from_region ()
1781 RegionSelection rs = get_regions_from_selection_and_entered ();
1787 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1788 XMLNode &before = _session->locations()->get_state();
1790 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1792 boost::shared_ptr<Region> region = (*i)->region ();
1794 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1796 _session->locations()->add (location, true);
1799 XMLNode &after = _session->locations()->get_state();
1800 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1801 _session->commit_reversible_command ();
1804 /** Add a single range marker around all selected regions */
1806 Editor::add_location_from_region ()
1808 RegionSelection rs = get_regions_from_selection_and_entered ();
1814 _session->begin_reversible_command (_("add marker"));
1815 XMLNode &before = _session->locations()->get_state();
1819 if (rs.size() > 1) {
1820 _session->locations()->next_available_name(markername, "regions");
1822 RegionView* rv = *(rs.begin());
1823 boost::shared_ptr<Region> region = rv->region();
1824 markername = region->name();
1827 if (!choose_new_marker_name(markername)) {
1831 // single range spanning all selected
1832 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1833 _session->locations()->add (location, true);
1835 XMLNode &after = _session->locations()->get_state();
1836 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1837 _session->commit_reversible_command ();
1843 Editor::jump_forward_to_mark ()
1849 Location *location = _session->locations()->first_location_after (playhead_cursor->current_frame);
1852 _session->request_locate (location->start(), _session->transport_rolling());
1854 _session->request_locate (_session->current_end_frame());
1859 Editor::jump_backward_to_mark ()
1865 Location *location = _session->locations()->first_location_before (playhead_cursor->current_frame);
1868 _session->request_locate (location->start(), _session->transport_rolling());
1870 _session->goto_start ();
1877 framepos_t const pos = _session->audible_frame ();
1880 _session->locations()->next_available_name (markername, "mark");
1882 if (!choose_new_marker_name (markername)) {
1886 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1890 Editor::clear_markers ()
1893 _session->begin_reversible_command (_("clear markers"));
1894 XMLNode &before = _session->locations()->get_state();
1895 _session->locations()->clear_markers ();
1896 XMLNode &after = _session->locations()->get_state();
1897 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1898 _session->commit_reversible_command ();
1903 Editor::clear_ranges ()
1906 _session->begin_reversible_command (_("clear ranges"));
1907 XMLNode &before = _session->locations()->get_state();
1909 Location * looploc = _session->locations()->auto_loop_location();
1910 Location * punchloc = _session->locations()->auto_punch_location();
1911 Location * sessionloc = _session->locations()->session_range_location();
1913 _session->locations()->clear_ranges ();
1915 if (looploc) _session->locations()->add (looploc);
1916 if (punchloc) _session->locations()->add (punchloc);
1917 if (sessionloc) _session->locations()->add (sessionloc);
1919 XMLNode &after = _session->locations()->get_state();
1920 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1921 _session->commit_reversible_command ();
1926 Editor::clear_locations ()
1928 _session->begin_reversible_command (_("clear locations"));
1929 XMLNode &before = _session->locations()->get_state();
1930 _session->locations()->clear ();
1931 XMLNode &after = _session->locations()->get_state();
1932 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1933 _session->commit_reversible_command ();
1934 _session->locations()->clear ();
1938 Editor::unhide_markers ()
1940 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1941 Location *l = (*i).first;
1942 if (l->is_hidden() && l->is_mark()) {
1943 l->set_hidden(false, this);
1949 Editor::unhide_ranges ()
1951 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1952 Location *l = (*i).first;
1953 if (l->is_hidden() && l->is_range_marker()) {
1954 l->set_hidden(false, this);
1959 /* INSERT/REPLACE */
1962 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1967 RouteTimeAxisView *rtv = 0;
1968 boost::shared_ptr<Playlist> playlist;
1970 track_canvas->window_to_world (x, y, wx, wy);
1973 event.type = GDK_BUTTON_RELEASE;
1974 event.button.x = wx;
1975 event.button.y = wy;
1977 where = event_frame (&event, &cx, &cy);
1979 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1980 /* clearly outside canvas area */
1984 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1985 if (tv.first == 0) {
1989 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1993 if ((playlist = rtv->playlist()) == 0) {
1999 begin_reversible_command (_("insert dragged region"));
2000 playlist->clear_changes ();
2001 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2002 _session->add_command(new StatefulDiffCommand (playlist));
2003 commit_reversible_command ();
2007 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2011 RouteTimeAxisView *dest_rtv = 0;
2012 RouteTimeAxisView *source_rtv = 0;
2014 track_canvas->window_to_world (x, y, wx, wy);
2015 wx += horizontal_position ();
2016 wy += vertical_adjustment.get_value();
2019 event.type = GDK_BUTTON_RELEASE;
2020 event.button.x = wx;
2021 event.button.y = wy;
2023 event_frame (&event, &cx, &cy);
2025 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2026 if (tv.first == 0) {
2030 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2034 /* use this drag source to add underlay to a track. But we really don't care
2035 about the Route, only the view of the route, so find it first */
2036 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2037 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2041 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2042 dest_rtv->add_underlay(source_rtv->view());
2049 Editor::insert_region_list_selection (float times)
2051 RouteTimeAxisView *tv = 0;
2052 boost::shared_ptr<Playlist> playlist;
2054 if (clicked_routeview != 0) {
2055 tv = clicked_routeview;
2056 } else if (!selection->tracks.empty()) {
2057 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2060 } else if (entered_track != 0) {
2061 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2068 if ((playlist = tv->playlist()) == 0) {
2072 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2077 begin_reversible_command (_("insert region"));
2078 playlist->clear_changes ();
2079 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2080 _session->add_command(new StatefulDiffCommand (playlist));
2081 commit_reversible_command ();
2084 /* BUILT-IN EFFECTS */
2087 Editor::reverse_selection ()
2092 /* GAIN ENVELOPE EDITING */
2095 Editor::edit_envelope ()
2102 Editor::transition_to_rolling (bool fwd)
2108 if (_session->config.get_external_sync()) {
2109 switch (Config->get_sync_source()) {
2113 /* transport controlled by the master */
2118 if (_session->is_auditioning()) {
2119 _session->cancel_audition ();
2123 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2127 Editor::play_from_start ()
2129 _session->request_locate (_session->current_start_frame(), true);
2133 Editor::play_from_edit_point ()
2135 _session->request_locate (get_preferred_edit_position(), true);
2139 Editor::play_from_edit_point_and_return ()
2141 framepos_t start_frame;
2142 framepos_t return_frame;
2144 start_frame = get_preferred_edit_position (true);
2146 if (_session->transport_rolling()) {
2147 _session->request_locate (start_frame, false);
2151 /* don't reset the return frame if its already set */
2153 if ((return_frame = _session->requested_return_frame()) < 0) {
2154 return_frame = _session->audible_frame();
2157 if (start_frame >= 0) {
2158 _session->request_roll_at_and_return (start_frame, return_frame);
2163 Editor::play_selection ()
2165 if (selection->time.empty()) {
2169 _session->request_play_range (&selection->time, true);
2173 Editor::play_location (Location& location)
2175 if (location.start() <= location.end()) {
2179 _session->request_bounded_roll (location.start(), location.end());
2183 Editor::loop_location (Location& location)
2185 if (location.start() <= location.end()) {
2191 if ((tll = transport_loop_location()) != 0) {
2192 tll->set (location.start(), location.end());
2194 // enable looping, reposition and start rolling
2195 _session->request_play_loop (true);
2196 _session->request_locate (tll->start(), true);
2201 Editor::do_layer_operation (LayerOperation op)
2203 if (selection->regions.empty ()) {
2207 bool const multiple = selection->regions.size() > 1;
2211 begin_reversible_command (_("raise regions"));
2213 begin_reversible_command (_("raise region"));
2219 begin_reversible_command (_("raise regions to top"));
2221 begin_reversible_command (_("raise region to top"));
2227 begin_reversible_command (_("lower regions"));
2229 begin_reversible_command (_("lower region"));
2235 begin_reversible_command (_("lower regions to bottom"));
2237 begin_reversible_command (_("lower region"));
2242 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2243 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2244 (*i)->clear_owned_changes ();
2247 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2248 boost::shared_ptr<Region> r = (*i)->region ();
2260 r->lower_to_bottom ();
2264 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2265 vector<Command*> cmds;
2267 _session->add_commands (cmds);
2270 commit_reversible_command ();
2274 Editor::raise_region ()
2276 do_layer_operation (Raise);
2280 Editor::raise_region_to_top ()
2282 do_layer_operation (RaiseToTop);
2286 Editor::lower_region ()
2288 do_layer_operation (Lower);
2292 Editor::lower_region_to_bottom ()
2294 do_layer_operation (LowerToBottom);
2297 /** Show the region editor for the selected regions */
2299 Editor::show_region_properties ()
2301 selection->foreach_regionview (&RegionView::show_region_editor);
2304 /** Show the midi list editor for the selected MIDI regions */
2306 Editor::show_midi_list_editor ()
2308 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2312 Editor::rename_region ()
2314 RegionSelection rs = get_regions_from_selection_and_entered ();
2320 ArdourDialog d (*this, _("Rename Region"), true, false);
2322 Label label (_("New name:"));
2325 hbox.set_spacing (6);
2326 hbox.pack_start (label, false, false);
2327 hbox.pack_start (entry, true, true);
2329 d.get_vbox()->set_border_width (12);
2330 d.get_vbox()->pack_start (hbox, false, false);
2332 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2333 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2335 d.set_size_request (300, -1);
2336 d.set_position (Gtk::WIN_POS_MOUSE);
2338 entry.set_text (rs.front()->region()->name());
2339 entry.select_region (0, -1);
2341 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2347 int const ret = d.run();
2351 if (ret != RESPONSE_OK) {
2355 std::string str = entry.get_text();
2356 strip_whitespace_edges (str);
2358 rs.front()->region()->set_name (str);
2359 _regions->redisplay ();
2364 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2366 if (_session->is_auditioning()) {
2367 _session->cancel_audition ();
2370 // note: some potential for creativity here, because region doesn't
2371 // have to belong to the playlist that Route is handling
2373 // bool was_soloed = route.soloed();
2375 route.set_solo (true, this);
2377 _session->request_bounded_roll (region->position(), region->position() + region->length());
2379 /* XXX how to unset the solo state ? */
2382 /** Start an audition of the first selected region */
2384 Editor::play_edit_range ()
2386 framepos_t start, end;
2388 if (get_edit_op_range (start, end)) {
2389 _session->request_bounded_roll (start, end);
2394 Editor::play_selected_region ()
2396 framepos_t start = max_framepos;
2399 RegionSelection rs = get_regions_from_selection_and_entered ();
2405 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2406 if ((*i)->region()->position() < start) {
2407 start = (*i)->region()->position();
2409 if ((*i)->region()->last_frame() + 1 > end) {
2410 end = (*i)->region()->last_frame() + 1;
2414 _session->request_bounded_roll (start, end);
2418 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2420 _session->audition_region (region);
2424 Editor::region_from_selection ()
2426 if (clicked_axisview == 0) {
2430 if (selection->time.empty()) {
2434 framepos_t start = selection->time[clicked_selection].start;
2435 framepos_t end = selection->time[clicked_selection].end;
2437 TrackViewList tracks = get_tracks_for_range_action ();
2439 framepos_t selection_cnt = end - start + 1;
2441 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2442 boost::shared_ptr<Region> current;
2443 boost::shared_ptr<Playlist> pl;
2444 framepos_t internal_start;
2447 if ((pl = (*i)->playlist()) == 0) {
2451 if ((current = pl->top_region_at (start)) == 0) {
2455 internal_start = start - current->position();
2456 RegionFactory::region_name (new_name, current->name(), true);
2460 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2461 plist.add (ARDOUR::Properties::length, selection_cnt);
2462 plist.add (ARDOUR::Properties::name, new_name);
2463 plist.add (ARDOUR::Properties::layer, 0);
2465 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2470 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2472 if (selection->time.empty() || selection->tracks.empty()) {
2476 framepos_t start = selection->time[clicked_selection].start;
2477 framepos_t end = selection->time[clicked_selection].end;
2479 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2480 sort_track_selection (ts);
2482 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2483 boost::shared_ptr<Region> current;
2484 boost::shared_ptr<Playlist> playlist;
2485 framepos_t internal_start;
2488 if ((playlist = (*i)->playlist()) == 0) {
2492 if ((current = playlist->top_region_at(start)) == 0) {
2496 internal_start = start - current->position();
2497 RegionFactory::region_name (new_name, current->name(), true);
2501 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2502 plist.add (ARDOUR::Properties::length, end - start + 1);
2503 plist.add (ARDOUR::Properties::name, new_name);
2505 new_regions.push_back (RegionFactory::create (current, plist));
2510 Editor::split_multichannel_region ()
2512 RegionSelection rs = get_regions_from_selection_and_entered ();
2518 vector< boost::shared_ptr<Region> > v;
2520 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2521 (*x)->region()->separate_by_channel (*_session, v);
2526 Editor::new_region_from_selection ()
2528 region_from_selection ();
2529 cancel_selection ();
2533 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2535 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2536 case Evoral::OverlapNone:
2544 * - selected tracks, or if there are none...
2545 * - tracks containing selected regions, or if there are none...
2550 Editor::get_tracks_for_range_action () const
2554 if (selection->tracks.empty()) {
2556 /* use tracks with selected regions */
2558 RegionSelection rs = selection->regions;
2560 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2561 TimeAxisView* tv = &(*i)->get_time_axis_view();
2563 if (!t.contains (tv)) {
2569 /* no regions and no tracks: use all tracks */
2575 t = selection->tracks;
2578 return t.filter_to_unique_playlists();
2582 Editor::separate_regions_between (const TimeSelection& ts)
2584 bool in_command = false;
2585 boost::shared_ptr<Playlist> playlist;
2586 RegionSelection new_selection;
2588 TrackViewList tmptracks = get_tracks_for_range_action ();
2589 sort_track_selection (tmptracks);
2591 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2593 RouteTimeAxisView* rtv;
2595 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2597 if (rtv->is_track()) {
2599 /* no edits to destructive tracks */
2601 if (rtv->track()->destructive()) {
2605 if ((playlist = rtv->playlist()) != 0) {
2607 playlist->clear_changes ();
2609 /* XXX need to consider musical time selections here at some point */
2611 double speed = rtv->track()->speed();
2614 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2616 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2617 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2619 latest_regionviews.clear ();
2621 playlist->partition ((framepos_t)((*t).start * speed),
2622 (framepos_t)((*t).end * speed), false);
2626 if (!latest_regionviews.empty()) {
2628 rtv->view()->foreach_regionview (sigc::bind (
2629 sigc::ptr_fun (add_if_covered),
2630 &(*t), &new_selection));
2633 begin_reversible_command (_("separate"));
2637 /* pick up changes to existing regions */
2639 vector<Command*> cmds;
2640 playlist->rdiff (cmds);
2641 _session->add_commands (cmds);
2643 /* pick up changes to the playlist itself (adds/removes)
2646 _session->add_command(new StatefulDiffCommand (playlist));
2655 selection->set (new_selection);
2656 set_mouse_mode (MouseObject);
2658 commit_reversible_command ();
2662 struct PlaylistState {
2663 boost::shared_ptr<Playlist> playlist;
2667 /** Take tracks from get_tracks_for_range_action and cut any regions
2668 * on those tracks so that the tracks are empty over the time
2672 Editor::separate_region_from_selection ()
2674 /* preferentially use *all* ranges in the time selection if we're in range mode
2675 to allow discontiguous operation, since get_edit_op_range() currently
2676 returns a single range.
2679 if (mouse_mode == MouseRange && !selection->time.empty()) {
2681 separate_regions_between (selection->time);
2688 if (get_edit_op_range (start, end)) {
2690 AudioRange ar (start, end, 1);
2694 separate_regions_between (ts);
2700 Editor::separate_region_from_punch ()
2702 Location* loc = _session->locations()->auto_punch_location();
2704 separate_regions_using_location (*loc);
2709 Editor::separate_region_from_loop ()
2711 Location* loc = _session->locations()->auto_loop_location();
2713 separate_regions_using_location (*loc);
2718 Editor::separate_regions_using_location (Location& loc)
2720 if (loc.is_mark()) {
2724 AudioRange ar (loc.start(), loc.end(), 1);
2729 separate_regions_between (ts);
2732 /** Separate regions under the selected region */
2734 Editor::separate_under_selected_regions ()
2736 vector<PlaylistState> playlists;
2740 rs = get_regions_from_selection_and_entered();
2742 if (!_session || rs.empty()) {
2746 begin_reversible_command (_("separate region under"));
2748 list<boost::shared_ptr<Region> > regions_to_remove;
2750 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2751 // we can't just remove the region(s) in this loop because
2752 // this removes them from the RegionSelection, and they thus
2753 // disappear from underneath the iterator, and the ++i above
2754 // SEGVs in a puzzling fashion.
2756 // so, first iterate over the regions to be removed from rs and
2757 // add them to the regions_to_remove list, and then
2758 // iterate over the list to actually remove them.
2760 regions_to_remove.push_back ((*i)->region());
2763 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2765 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2768 // is this check necessary?
2772 vector<PlaylistState>::iterator i;
2774 //only take state if this is a new playlist.
2775 for (i = playlists.begin(); i != playlists.end(); ++i) {
2776 if ((*i).playlist == playlist) {
2781 if (i == playlists.end()) {
2783 PlaylistState before;
2784 before.playlist = playlist;
2785 before.before = &playlist->get_state();
2787 playlist->freeze ();
2788 playlists.push_back(before);
2791 //Partition on the region bounds
2792 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2794 //Re-add region that was just removed due to the partition operation
2795 playlist->add_region( (*rl), (*rl)->first_frame() );
2798 vector<PlaylistState>::iterator pl;
2800 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2801 (*pl).playlist->thaw ();
2802 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2805 commit_reversible_command ();
2809 Editor::crop_region_to_selection ()
2811 if (!selection->time.empty()) {
2813 crop_region_to (selection->time.start(), selection->time.end_frame());
2820 if (get_edit_op_range (start, end)) {
2821 crop_region_to (start, end);
2828 Editor::crop_region_to (framepos_t start, framepos_t end)
2830 vector<boost::shared_ptr<Playlist> > playlists;
2831 boost::shared_ptr<Playlist> playlist;
2834 if (selection->tracks.empty()) {
2835 ts = track_views.filter_to_unique_playlists();
2837 ts = selection->tracks.filter_to_unique_playlists ();
2840 sort_track_selection (ts);
2842 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2844 RouteTimeAxisView* rtv;
2846 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2848 boost::shared_ptr<Track> t = rtv->track();
2850 if (t != 0 && ! t->destructive()) {
2852 if ((playlist = rtv->playlist()) != 0) {
2853 playlists.push_back (playlist);
2859 if (playlists.empty()) {
2863 framepos_t the_start;
2867 begin_reversible_command (_("trim to selection"));
2869 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2871 boost::shared_ptr<Region> region;
2875 if ((region = (*i)->top_region_at(the_start)) == 0) {
2879 /* now adjust lengths to that we do the right thing
2880 if the selection extends beyond the region
2883 the_start = max (the_start, (framepos_t) region->position());
2884 if (max_framepos - the_start < region->length()) {
2885 the_end = the_start + region->length() - 1;
2887 the_end = max_framepos;
2889 the_end = min (end, the_end);
2890 cnt = the_end - the_start + 1;
2892 region->clear_changes ();
2893 region->trim_to (the_start, cnt);
2894 _session->add_command (new StatefulDiffCommand (region));
2897 commit_reversible_command ();
2901 Editor::region_fill_track ()
2903 RegionSelection rs = get_regions_from_selection_and_entered ();
2905 if (!_session || rs.empty()) {
2909 framepos_t const end = _session->current_end_frame ();
2911 begin_reversible_command (Operations::region_fill);
2913 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2915 boost::shared_ptr<Region> region ((*i)->region());
2917 boost::shared_ptr<Playlist> pl = region->playlist();
2919 if (end <= region->last_frame()) {
2923 double times = (double) (end - region->last_frame()) / (double) region->length();
2929 pl->clear_changes ();
2930 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2931 _session->add_command (new StatefulDiffCommand (pl));
2934 commit_reversible_command ();
2938 Editor::region_fill_selection ()
2940 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2944 if (selection->time.empty()) {
2948 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2953 framepos_t start = selection->time[clicked_selection].start;
2954 framepos_t end = selection->time[clicked_selection].end;
2956 boost::shared_ptr<Playlist> playlist;
2958 if (selection->tracks.empty()) {
2962 framepos_t selection_length = end - start;
2963 float times = (float)selection_length / region->length();
2965 begin_reversible_command (Operations::fill_selection);
2967 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2969 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
2971 if ((playlist = (*i)->playlist()) == 0) {
2975 playlist->clear_changes ();
2976 playlist->add_region (RegionFactory::create (region, true), start, times);
2977 _session->add_command (new StatefulDiffCommand (playlist));
2980 commit_reversible_command ();
2984 Editor::set_region_sync_position ()
2986 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
2990 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
2992 bool in_command = false;
2994 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
2996 if (!(*r)->region()->covers (where)) {
3000 boost::shared_ptr<Region> region ((*r)->region());
3003 begin_reversible_command (_("set sync point"));
3007 region->clear_changes ();
3008 region->set_sync_position (where);
3009 _session->add_command(new StatefulDiffCommand (region));
3013 commit_reversible_command ();
3017 /** Remove the sync positions of the selection */
3019 Editor::remove_region_sync ()
3021 RegionSelection rs = get_regions_from_selection_and_entered ();
3027 begin_reversible_command (_("remove region sync"));
3029 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3031 (*i)->region()->clear_changes ();
3032 (*i)->region()->clear_sync_position ();
3033 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3036 commit_reversible_command ();
3040 Editor::naturalize_region ()
3042 RegionSelection rs = get_regions_from_selection_and_entered ();
3048 if (rs.size() > 1) {
3049 begin_reversible_command (_("move regions to original position"));
3051 begin_reversible_command (_("move region to original position"));
3054 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3055 (*i)->region()->clear_changes ();
3056 (*i)->region()->move_to_natural_position ();
3057 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3060 commit_reversible_command ();
3064 Editor::align_regions (RegionPoint what)
3066 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3072 begin_reversible_command (_("align selection"));
3074 framepos_t const position = get_preferred_edit_position ();
3076 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3077 align_region_internal ((*i)->region(), what, position);
3080 commit_reversible_command ();
3083 struct RegionSortByTime {
3084 bool operator() (const RegionView* a, const RegionView* b) {
3085 return a->region()->position() < b->region()->position();
3090 Editor::align_regions_relative (RegionPoint point)
3092 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3098 framepos_t const position = get_preferred_edit_position ();
3100 framepos_t distance = 0;
3104 list<RegionView*> sorted;
3105 rs.by_position (sorted);
3107 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3112 if (position > r->position()) {
3113 distance = position - r->position();
3115 distance = r->position() - position;
3121 if (position > r->last_frame()) {
3122 distance = position - r->last_frame();
3123 pos = r->position() + distance;
3125 distance = r->last_frame() - position;
3126 pos = r->position() - distance;
3132 pos = r->adjust_to_sync (position);
3133 if (pos > r->position()) {
3134 distance = pos - r->position();
3136 distance = r->position() - pos;
3142 if (pos == r->position()) {
3146 begin_reversible_command (_("align selection (relative)"));
3148 /* move first one specially */
3150 r->clear_changes ();
3151 r->set_position (pos);
3152 _session->add_command(new StatefulDiffCommand (r));
3154 /* move rest by the same amount */
3158 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3160 boost::shared_ptr<Region> region ((*i)->region());
3162 region->clear_changes ();
3165 region->set_position (region->position() + distance);
3167 region->set_position (region->position() - distance);
3170 _session->add_command(new StatefulDiffCommand (region));
3174 commit_reversible_command ();
3178 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3180 begin_reversible_command (_("align region"));
3181 align_region_internal (region, point, position);
3182 commit_reversible_command ();
3186 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3188 region->clear_changes ();
3192 region->set_position (region->adjust_to_sync (position));
3196 if (position > region->length()) {
3197 region->set_position (position - region->length());
3202 region->set_position (position);
3206 _session->add_command(new StatefulDiffCommand (region));
3210 Editor::trim_region_front ()
3216 Editor::trim_region_back ()
3218 trim_region (false);
3222 Editor::trim_region (bool front)
3224 framepos_t where = get_preferred_edit_position();
3225 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3231 begin_reversible_command (front ? _("trim front") : _("trim back"));
3233 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3234 if (!(*i)->region()->locked()) {
3236 (*i)->region()->clear_changes ();
3239 (*i)->region()->trim_front (where);
3241 (*i)->region()->trim_end (where);
3244 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3248 commit_reversible_command ();
3251 /** Trim the end of the selected regions to the position of the edit cursor */
3253 Editor::trim_region_to_loop ()
3255 Location* loc = _session->locations()->auto_loop_location();
3259 trim_region_to_location (*loc, _("trim to loop"));
3263 Editor::trim_region_to_punch ()
3265 Location* loc = _session->locations()->auto_punch_location();
3269 trim_region_to_location (*loc, _("trim to punch"));
3273 Editor::trim_region_to_location (const Location& loc, const char* str)
3275 RegionSelection rs = get_regions_from_selection_and_entered ();
3277 begin_reversible_command (str);
3279 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3280 RegionView* rv = (*x);
3282 /* require region to span proposed trim */
3283 switch (rv->region()->coverage (loc.start(), loc.end())) {
3284 case Evoral::OverlapInternal:
3290 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3299 if (tav->track() != 0) {
3300 speed = tav->track()->speed();
3303 start = session_frame_to_track_frame (loc.start(), speed);
3304 end = session_frame_to_track_frame (loc.end(), speed);
3306 rv->region()->clear_changes ();
3307 rv->region()->trim_to (start, (end - start));
3308 _session->add_command(new StatefulDiffCommand (rv->region()));
3311 commit_reversible_command ();
3315 Editor::trim_region_to_previous_region_end ()
3317 return trim_to_region(false);
3321 Editor::trim_region_to_next_region_start ()
3323 return trim_to_region(true);
3327 Editor::trim_to_region(bool forward)
3329 RegionSelection rs = get_regions_from_selection_and_entered ();
3331 begin_reversible_command (_("trim to region"));
3333 boost::shared_ptr<Region> next_region;
3335 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3337 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3343 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3351 if (atav->track() != 0) {
3352 speed = atav->track()->speed();
3356 boost::shared_ptr<Region> region = arv->region();
3357 boost::shared_ptr<Playlist> playlist (region->playlist());
3359 region->clear_changes ();
3363 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3369 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3370 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3374 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3380 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3382 arv->region_changed (ARDOUR::bounds_change);
3385 _session->add_command(new StatefulDiffCommand (region));
3388 commit_reversible_command ();
3392 Editor::unfreeze_route ()
3394 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3398 clicked_routeview->track()->unfreeze ();
3402 Editor::_freeze_thread (void* arg)
3404 return static_cast<Editor*>(arg)->freeze_thread ();
3408 Editor::freeze_thread ()
3410 /* create event pool because we may need to talk to the session */
3411 SessionEvent::create_per_thread_pool ("freeze events", 64);
3412 /* create per-thread buffers for process() tree to use */
3413 current_interthread_info->process_thread.get_buffers ();
3414 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3415 current_interthread_info->done = true;
3416 current_interthread_info->process_thread.drop_buffers();
3421 Editor::freeze_route ()
3427 /* stop transport before we start. this is important */
3429 _session->request_transport_speed (0.0);
3431 /* wait for just a little while, because the above call is asynchronous */
3435 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3439 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3441 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3442 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3444 d.set_title (_("Cannot freeze"));
3449 if (clicked_routeview->track()->has_external_redirects()) {
3450 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"
3451 "Freezing will only process the signal as far as the first send/insert/return."),
3452 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3454 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3455 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3456 d.set_title (_("Freeze Limits"));
3458 int response = d.run ();
3461 case Gtk::RESPONSE_CANCEL:
3468 InterThreadInfo itt;
3469 current_interthread_info = &itt;
3471 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3473 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3475 set_canvas_cursor (_cursors->wait);
3477 while (!itt.done && !itt.cancel) {
3478 gtk_main_iteration ();
3481 current_interthread_info = 0;
3482 set_canvas_cursor (current_canvas_cursor);
3486 Editor::bounce_range_selection (bool replace, bool enable_processing)
3488 if (selection->time.empty()) {
3492 TrackSelection views = selection->tracks;
3494 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3496 if (enable_processing) {
3498 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3500 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3502 _("You can't perform this operation because the processing of the signal "
3503 "will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
3504 "You can do this without processing, which is a different operation.")
3506 d.set_title (_("Cannot bounce"));
3513 framepos_t start = selection->time[clicked_selection].start;
3514 framepos_t end = selection->time[clicked_selection].end;
3515 framepos_t cnt = end - start + 1;
3517 begin_reversible_command (_("bounce range"));
3519 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3521 RouteTimeAxisView* rtv;
3523 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3527 boost::shared_ptr<Playlist> playlist;
3529 if ((playlist = rtv->playlist()) == 0) {
3533 InterThreadInfo itt;
3535 playlist->clear_changes ();
3536 playlist->clear_owned_changes ();
3538 boost::shared_ptr<Region> r;
3540 if (enable_processing) {
3541 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3543 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3551 list<AudioRange> ranges;
3552 ranges.push_back (AudioRange (start, start+cnt, 0));
3553 playlist->cut (ranges); // discard result
3554 playlist->add_region (r, start);
3557 vector<Command*> cmds;
3558 playlist->rdiff (cmds);
3559 _session->add_commands (cmds);
3561 _session->add_command (new StatefulDiffCommand (playlist));
3564 commit_reversible_command ();
3567 /** Delete selected regions, automation points or a time range */
3574 /** Cut selected regions, automation points or a time range */
3581 /** Copy selected regions, automation points or a time range */
3589 /** @return true if a Cut, Copy or Clear is possible */
3591 Editor::can_cut_copy () const
3593 switch (current_mouse_mode()) {
3596 if (!selection->regions.empty() || !selection->points.empty()) {
3602 if (!selection->time.empty()) {
3615 /** Cut, copy or clear selected regions, automation points or a time range.
3616 * @param op Operation (Cut, Copy or Clear)
3619 Editor::cut_copy (CutCopyOp op)
3621 /* only cancel selection if cut/copy is successful.*/
3627 opname = _("delete");
3636 opname = _("clear");
3640 /* if we're deleting something, and the mouse is still pressed,
3641 the thing we started a drag for will be gone when we release
3642 the mouse button(s). avoid this. see part 2 at the end of
3646 if (op == Delete || op == Cut || op == Clear) {
3647 if (_drags->active ()) {
3652 cut_buffer->clear ();
3654 if (entered_marker) {
3656 /* cut/delete op while pointing at a marker */
3659 Location* loc = find_location_from_marker (entered_marker, ignored);
3661 if (_session && loc) {
3662 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3669 if (internal_editing()) {
3671 switch (current_mouse_mode()) {
3684 /* we only want to cut regions if some are selected */
3686 if (doing_object_stuff()) {
3687 rs = get_regions_from_selection ();
3688 if (!rs.empty() || !selection->points.empty()) {
3690 begin_reversible_command (opname + _(" objects"));
3693 cut_copy_regions (op, rs);
3695 if (op == Cut || op == Delete) {
3696 selection->clear_regions ();
3700 if (!selection->points.empty()) {
3701 cut_copy_points (op);
3703 if (op == Cut || op == Delete) {
3704 selection->clear_points ();
3707 commit_reversible_command ();
3710 if (!selection->time.empty() && (_join_object_range_state == JOIN_OBJECT_RANGE_NONE)) {
3711 /* don't cause suprises */
3716 if (doing_range_stuff()) {
3717 if (selection->time.empty()) {
3718 framepos_t start, end;
3719 if (!get_edit_op_range (start, end)) {
3722 selection->set (start, end);
3725 begin_reversible_command (opname + _(" range"));
3726 cut_copy_ranges (op);
3727 commit_reversible_command ();
3729 if (op == Cut || op == Delete) {
3730 selection->clear_time ();
3736 if (op == Delete || op == Cut || op == Clear) {
3741 struct AutomationRecord {
3742 AutomationRecord () : state (0) {}
3743 AutomationRecord (XMLNode* s) : state (s) {}
3745 XMLNode* state; ///< state before any operation
3746 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3749 /** Cut, copy or clear selected automation points.
3750 * @param op Operation (Cut, Copy or Clear)
3753 Editor::cut_copy_points (CutCopyOp op)
3755 if (selection->points.empty ()) {
3759 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3760 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3762 /* Keep a record of the AutomationLists that we end up using in this operation */
3763 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3766 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3767 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3768 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3769 if (lists.find (al) == lists.end ()) {
3770 /* We haven't seen this list yet, so make a record for it. This includes
3771 taking a copy of its current state, in case this is needed for undo later.
3773 lists[al] = AutomationRecord (&al->get_state ());
3777 if (op == Cut || op == Copy) {
3778 /* This operation will involve putting things in the cut buffer, so create an empty
3779 ControlList for each of our source lists to put the cut buffer data in.
3781 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3782 i->second.copy = i->first->create (i->first->parameter ());
3785 /* Add all selected points to the relevant copy ControlLists */
3786 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3787 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3788 AutomationList::const_iterator j = (*i)->model ();
3789 lists[al].copy->add ((*j)->when, (*j)->value);
3792 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3793 /* Correct this copy list so that it starts at time 0 */
3794 double const start = i->second.copy->front()->when;
3795 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3796 (*j)->when -= start;
3799 /* And add it to the cut buffer */
3800 cut_buffer->add (i->second.copy);
3804 if (op == Delete || op == Cut) {
3805 /* This operation needs to remove things from the main AutomationList, so do that now */
3807 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3808 i->first->freeze ();
3811 /* Remove each selected point from its AutomationList */
3812 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3813 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3814 al->erase ((*i)->model ());
3817 /* Thaw the lists and add undo records for them */
3818 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3819 boost::shared_ptr<AutomationList> al = i->first;
3821 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3826 /** Cut, copy or clear selected automation points.
3827 * @param op Operation (Cut, Copy or Clear)
3830 Editor::cut_copy_midi (CutCopyOp op)
3832 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3833 MidiRegionView* mrv = *i;
3834 mrv->cut_copy_clear (op);
3840 struct lt_playlist {
3841 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3842 return a.playlist < b.playlist;
3846 struct PlaylistMapping {
3848 boost::shared_ptr<Playlist> pl;
3850 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3853 /** Remove `clicked_regionview' */
3855 Editor::remove_clicked_region ()
3857 if (clicked_routeview == 0 || clicked_regionview == 0) {
3861 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3863 begin_reversible_command (_("remove region"));
3864 playlist->clear_changes ();
3865 playlist->clear_owned_changes ();
3866 playlist->remove_region (clicked_regionview->region());
3868 /* We might have removed regions, which alters other regions' layering_index,
3869 so we need to do a recursive diff here.
3871 vector<Command*> cmds;
3872 playlist->rdiff (cmds);
3873 _session->add_commands (cmds);
3875 _session->add_command(new StatefulDiffCommand (playlist));
3876 commit_reversible_command ();
3880 /** Remove the selected regions */
3882 Editor::remove_selected_regions ()
3884 RegionSelection rs = get_regions_from_selection_and_entered ();
3886 if (!_session || rs.empty()) {
3890 begin_reversible_command (_("remove region"));
3892 list<boost::shared_ptr<Region> > regions_to_remove;
3894 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3895 // we can't just remove the region(s) in this loop because
3896 // this removes them from the RegionSelection, and they thus
3897 // disappear from underneath the iterator, and the ++i above
3898 // SEGVs in a puzzling fashion.
3900 // so, first iterate over the regions to be removed from rs and
3901 // add them to the regions_to_remove list, and then
3902 // iterate over the list to actually remove them.
3904 regions_to_remove.push_back ((*i)->region());
3907 vector<boost::shared_ptr<Playlist> > playlists;
3909 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3911 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3914 // is this check necessary?
3918 /* get_regions_from_selection_and_entered() guarantees that
3919 the playlists involved are unique, so there is no need
3923 playlists.push_back (playlist);
3925 playlist->clear_changes ();
3926 playlist->clear_owned_changes ();
3927 playlist->freeze ();
3928 playlist->remove_region (*rl);
3931 vector<boost::shared_ptr<Playlist> >::iterator pl;
3933 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3936 /* We might have removed regions, which alters other regions' layering_index,
3937 so we need to do a recursive diff here.
3939 vector<Command*> cmds;
3940 (*pl)->rdiff (cmds);
3941 _session->add_commands (cmds);
3943 _session->add_command(new StatefulDiffCommand (*pl));
3946 commit_reversible_command ();
3949 /** Cut, copy or clear selected regions.
3950 * @param op Operation (Cut, Copy or Clear)
3953 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
3955 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3956 a map when we want ordered access to both elements. i think.
3959 vector<PlaylistMapping> pmap;
3961 framepos_t first_position = max_framepos;
3963 typedef set<boost::shared_ptr<Playlist> > FreezeList;
3964 FreezeList freezelist;
3966 /* get ordering correct before we cut/copy */
3968 rs.sort_by_position_and_track ();
3970 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3972 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
3974 if (op == Cut || op == Clear || op == Delete) {
3975 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3978 FreezeList::iterator fl;
3980 // only take state if this is a new playlist.
3981 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
3987 if (fl == freezelist.end()) {
3988 pl->clear_changes();
3989 pl->clear_owned_changes ();
3991 freezelist.insert (pl);
3996 TimeAxisView* tv = &(*x)->get_time_axis_view();
3997 vector<PlaylistMapping>::iterator z;
3999 for (z = pmap.begin(); z != pmap.end(); ++z) {
4000 if ((*z).tv == tv) {
4005 if (z == pmap.end()) {
4006 pmap.push_back (PlaylistMapping (tv));
4010 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4012 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4015 /* region not yet associated with a playlist (e.g. unfinished
4022 TimeAxisView& tv = (*x)->get_time_axis_view();
4023 boost::shared_ptr<Playlist> npl;
4024 RegionSelection::iterator tmp;
4031 vector<PlaylistMapping>::iterator z;
4033 for (z = pmap.begin(); z != pmap.end(); ++z) {
4034 if ((*z).tv == &tv) {
4039 assert (z != pmap.end());
4042 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4050 boost::shared_ptr<Region> r = (*x)->region();
4051 boost::shared_ptr<Region> _xx;
4057 pl->remove_region (r);
4061 _xx = RegionFactory::create (r);
4062 npl->add_region (_xx, r->position() - first_position);
4063 pl->remove_region (r);
4067 /* copy region before adding, so we're not putting same object into two different playlists */
4068 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4072 pl->remove_region (r);
4081 list<boost::shared_ptr<Playlist> > foo;
4083 /* the pmap is in the same order as the tracks in which selected regions occured */
4085 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4088 foo.push_back ((*i).pl);
4093 cut_buffer->set (foo);
4097 _last_cut_copy_source_track = 0;
4099 _last_cut_copy_source_track = pmap.front().tv;
4103 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4106 /* We might have removed regions, which alters other regions' layering_index,
4107 so we need to do a recursive diff here.
4109 vector<Command*> cmds;
4110 (*pl)->rdiff (cmds);
4111 _session->add_commands (cmds);
4113 _session->add_command (new StatefulDiffCommand (*pl));
4118 Editor::cut_copy_ranges (CutCopyOp op)
4120 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4122 /* Sort the track selection now, so that it if is used, the playlists
4123 selected by the calls below to cut_copy_clear are in the order that
4124 their tracks appear in the editor. This makes things like paste
4125 of ranges work properly.
4128 sort_track_selection (ts);
4131 if (!entered_track) {
4134 ts.push_back (entered_track);
4137 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4138 (*i)->cut_copy_clear (*selection, op);
4143 Editor::paste (float times, bool from_context)
4145 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4147 paste_internal (get_preferred_edit_position (false, from_context), times);
4151 Editor::mouse_paste ()
4156 if (!mouse_frame (where, ignored)) {
4161 paste_internal (where, 1);
4165 Editor::paste_internal (framepos_t position, float times)
4167 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4169 if (internal_editing()) {
4170 if (cut_buffer->midi_notes.empty()) {
4174 if (cut_buffer->empty()) {
4179 if (position == max_framepos) {
4180 position = get_preferred_edit_position();
4181 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4185 TrackViewList::iterator i;
4188 /* get everything in the correct order */
4190 if (_edit_point == Editing::EditAtMouse && entered_track) {
4191 /* With the mouse edit point, paste onto the track under the mouse */
4192 ts.push_back (entered_track);
4193 } else if (!selection->tracks.empty()) {
4194 /* Otherwise, if there are some selected tracks, paste to them */
4195 ts = selection->tracks.filter_to_unique_playlists ();
4196 sort_track_selection (ts);
4197 } else if (_last_cut_copy_source_track) {
4198 /* Otherwise paste to the track that the cut/copy came from;
4199 see discussion in mantis #3333.
4201 ts.push_back (_last_cut_copy_source_track);
4204 if (internal_editing ()) {
4206 /* undo/redo is handled by individual tracks/regions */
4208 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4211 RegionSelection::iterator r;
4212 MidiNoteSelection::iterator cb;
4214 get_regions_at (rs, position, ts);
4216 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4217 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4218 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4220 mrv->paste (position, times, **cb);
4228 /* we do redo (do you do voodoo?) */
4230 begin_reversible_command (Operations::paste);
4232 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4233 (*i)->paste (position, times, *cut_buffer, nth);
4236 commit_reversible_command ();
4241 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4243 boost::shared_ptr<Playlist> playlist;
4244 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4245 RegionSelection foo;
4247 framepos_t const start_frame = regions.start ();
4248 framepos_t const end_frame = regions.end_frame ();
4250 begin_reversible_command (Operations::duplicate_region);
4252 selection->clear_regions ();
4254 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4256 boost::shared_ptr<Region> r ((*i)->region());
4258 TimeAxisView& tv = (*i)->get_time_axis_view();
4259 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4260 latest_regionviews.clear ();
4261 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4263 playlist = (*i)->region()->playlist();
4264 playlist->clear_changes ();
4265 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4266 _session->add_command(new StatefulDiffCommand (playlist));
4270 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4273 commit_reversible_command ();
4276 selection->set (foo);
4281 Editor::duplicate_selection (float times)
4283 if (selection->time.empty() || selection->tracks.empty()) {
4287 boost::shared_ptr<Playlist> playlist;
4288 vector<boost::shared_ptr<Region> > new_regions;
4289 vector<boost::shared_ptr<Region> >::iterator ri;
4291 create_region_from_selection (new_regions);
4293 if (new_regions.empty()) {
4297 begin_reversible_command (_("duplicate selection"));
4299 ri = new_regions.begin();
4301 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4303 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4304 if ((playlist = (*i)->playlist()) == 0) {
4307 playlist->clear_changes ();
4308 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4309 _session->add_command (new StatefulDiffCommand (playlist));
4312 if (ri == new_regions.end()) {
4317 commit_reversible_command ();
4320 /** Reset all selected points to the relevant default value */
4322 Editor::reset_point_selection ()
4324 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4325 ARDOUR::AutomationList::iterator j = (*i)->model ();
4326 (*j)->value = (*i)->line().the_list()->default_value ();
4331 Editor::center_playhead ()
4333 float page = _canvas_width * frames_per_unit;
4334 center_screen_internal (playhead_cursor->current_frame, page);
4338 Editor::center_edit_point ()
4340 float page = _canvas_width * frames_per_unit;
4341 center_screen_internal (get_preferred_edit_position(), page);
4344 /** Caller must begin and commit a reversible command */
4346 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4348 playlist->clear_changes ();
4350 _session->add_command (new StatefulDiffCommand (playlist));
4354 Editor::nudge_track (bool use_edit, bool forwards)
4356 boost::shared_ptr<Playlist> playlist;
4357 framepos_t distance;
4358 framepos_t next_distance;
4362 start = get_preferred_edit_position();
4367 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4371 if (selection->tracks.empty()) {
4375 begin_reversible_command (_("nudge track"));
4377 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4379 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4381 if ((playlist = (*i)->playlist()) == 0) {
4385 playlist->clear_changes ();
4386 playlist->clear_owned_changes ();
4388 playlist->nudge_after (start, distance, forwards);
4390 vector<Command*> cmds;
4392 playlist->rdiff (cmds);
4393 _session->add_commands (cmds);
4395 _session->add_command (new StatefulDiffCommand (playlist));
4398 commit_reversible_command ();
4402 Editor::remove_last_capture ()
4404 vector<string> choices;
4411 if (Config->get_verify_remove_last_capture()) {
4412 prompt = _("Do you really want to destroy the last capture?"
4413 "\n(This is destructive and cannot be undone)");
4415 choices.push_back (_("No, do nothing."));
4416 choices.push_back (_("Yes, destroy it."));
4418 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4420 if (prompter.run () == 1) {
4421 _session->remove_last_capture ();
4422 _regions->redisplay ();
4426 _session->remove_last_capture();
4427 _regions->redisplay ();
4432 Editor::normalize_region ()
4438 RegionSelection rs = get_regions_from_selection_and_entered ();
4444 NormalizeDialog dialog (rs.size() > 1);
4446 if (dialog.run () == RESPONSE_CANCEL) {
4450 set_canvas_cursor (_cursors->wait);
4453 /* XXX: should really only count audio regions here */
4454 int const regions = rs.size ();
4456 /* Make a list of the selected audio regions' maximum amplitudes, and also
4457 obtain the maximum amplitude of them all.
4459 list<double> max_amps;
4461 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4462 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4464 dialog.descend (1.0 / regions);
4465 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4468 /* the user cancelled the operation */
4469 set_canvas_cursor (current_canvas_cursor);
4473 max_amps.push_back (a);
4474 max_amp = max (max_amp, a);
4479 begin_reversible_command (_("normalize"));
4481 list<double>::const_iterator a = max_amps.begin ();
4483 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4484 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4489 arv->region()->clear_changes ();
4491 double const amp = dialog.normalize_individually() ? *a : max_amp;
4493 arv->audio_region()->normalize (amp, dialog.target ());
4494 _session->add_command (new StatefulDiffCommand (arv->region()));
4499 commit_reversible_command ();
4500 set_canvas_cursor (current_canvas_cursor);
4505 Editor::reset_region_scale_amplitude ()
4511 RegionSelection rs = get_regions_from_selection_and_entered ();
4517 begin_reversible_command ("reset gain");
4519 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4520 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4523 arv->region()->clear_changes ();
4524 arv->audio_region()->set_scale_amplitude (1.0f);
4525 _session->add_command (new StatefulDiffCommand (arv->region()));
4528 commit_reversible_command ();
4532 Editor::adjust_region_gain (bool up)
4534 RegionSelection rs = get_regions_from_selection_and_entered ();
4536 if (!_session || rs.empty()) {
4540 begin_reversible_command ("adjust region gain");
4542 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4543 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4548 arv->region()->clear_changes ();
4550 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4558 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4559 _session->add_command (new StatefulDiffCommand (arv->region()));
4562 commit_reversible_command ();
4567 Editor::reverse_region ()
4573 Reverse rev (*_session);
4574 apply_filter (rev, _("reverse regions"));
4578 Editor::strip_region_silence ()
4584 RegionSelection rs = get_regions_from_selection_and_entered ();
4590 std::list<RegionView*> audio_only;
4592 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4593 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4595 audio_only.push_back (arv);
4599 StripSilenceDialog d (_session, audio_only);
4600 int const r = d.run ();
4604 if (r == Gtk::RESPONSE_OK) {
4605 ARDOUR::AudioIntervalMap silences;
4606 d.silences (silences);
4607 StripSilence s (*_session, silences, d.fade_length());
4608 apply_filter (s, _("strip silence"), &d);
4613 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4615 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4616 mrv.selection_as_notelist (selected, true);
4618 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4619 v.push_back (selected);
4621 framepos_t pos_frames = mrv.midi_region()->position();
4622 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4624 return op (mrv.midi_region()->model(), pos_beats, v);
4628 Editor::apply_midi_note_edit_op (MidiOperator& op)
4632 RegionSelection rs = get_regions_from_selection_and_entered ();
4638 begin_reversible_command (op.name ());
4640 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4641 RegionSelection::iterator tmp = r;
4644 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4647 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4650 _session->add_command (cmd);
4657 commit_reversible_command ();
4661 Editor::fork_region ()
4663 RegionSelection rs = get_regions_from_selection_and_entered ();
4669 begin_reversible_command (_("Fork Region(s)"));
4671 set_canvas_cursor (_cursors->wait);
4674 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4675 RegionSelection::iterator tmp = r;
4678 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4681 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4682 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4684 playlist->clear_changes ();
4685 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4686 _session->add_command(new StatefulDiffCommand (playlist));
4692 commit_reversible_command ();
4694 set_canvas_cursor (current_canvas_cursor);
4698 Editor::quantize_region ()
4700 int selected_midi_region_cnt = 0;
4706 RegionSelection rs = get_regions_from_selection_and_entered ();
4712 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4713 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4715 selected_midi_region_cnt++;
4719 if (selected_midi_region_cnt == 0) {
4723 QuantizeDialog* qd = new QuantizeDialog (*this);
4726 const int r = qd->run ();
4729 if (r == Gtk::RESPONSE_OK) {
4730 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4731 qd->start_grid_size(), qd->end_grid_size(),
4732 qd->strength(), qd->swing(), qd->threshold());
4734 apply_midi_note_edit_op (quant);
4739 Editor::insert_patch_change (bool from_context)
4741 RegionSelection rs = get_regions_from_selection_and_entered ();
4747 const framepos_t p = get_preferred_edit_position (false, from_context);
4749 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4750 there may be more than one, but the PatchChangeDialog can only offer
4751 one set of patch menus.
4753 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4755 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4756 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4758 if (d.run() == RESPONSE_CANCEL) {
4762 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4763 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4765 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4766 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4773 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4775 RegionSelection rs = get_regions_from_selection_and_entered ();
4781 begin_reversible_command (command);
4783 set_canvas_cursor (_cursors->wait);
4787 int const N = rs.size ();
4789 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4790 RegionSelection::iterator tmp = r;
4793 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4795 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4798 progress->descend (1.0 / N);
4801 if (arv->audio_region()->apply (filter, progress) == 0) {
4803 playlist->clear_changes ();
4804 playlist->clear_owned_changes ();
4806 if (filter.results.empty ()) {
4808 /* no regions returned; remove the old one */
4809 playlist->remove_region (arv->region ());
4813 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4815 /* first region replaces the old one */
4816 playlist->replace_region (arv->region(), *res, (*res)->position());
4820 while (res != filter.results.end()) {
4821 playlist->add_region (*res, (*res)->position());
4827 /* We might have removed regions, which alters other regions' layering_index,
4828 so we need to do a recursive diff here.
4830 vector<Command*> cmds;
4831 playlist->rdiff (cmds);
4832 _session->add_commands (cmds);
4834 _session->add_command(new StatefulDiffCommand (playlist));
4840 progress->ascend ();
4848 commit_reversible_command ();
4851 set_canvas_cursor (current_canvas_cursor);
4855 Editor::external_edit_region ()
4861 Editor::reset_region_gain_envelopes ()
4863 RegionSelection rs = get_regions_from_selection_and_entered ();
4865 if (!_session || rs.empty()) {
4869 _session->begin_reversible_command (_("reset region gain"));
4871 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4872 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4874 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4875 XMLNode& before (alist->get_state());
4877 arv->audio_region()->set_default_envelope ();
4878 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4882 _session->commit_reversible_command ();
4886 Editor::set_region_gain_visibility (RegionView* rv)
4888 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4890 arv->update_envelope_visibility();
4895 Editor::set_gain_envelope_visibility ()
4901 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4902 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4904 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
4910 Editor::toggle_gain_envelope_active ()
4912 if (_ignore_region_action) {
4916 RegionSelection rs = get_regions_from_selection_and_entered ();
4918 if (!_session || rs.empty()) {
4922 _session->begin_reversible_command (_("region gain envelope active"));
4924 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4925 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4927 arv->region()->clear_changes ();
4928 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
4929 _session->add_command (new StatefulDiffCommand (arv->region()));
4933 _session->commit_reversible_command ();
4937 Editor::toggle_region_lock ()
4939 if (_ignore_region_action) {
4943 RegionSelection rs = get_regions_from_selection_and_entered ();
4945 if (!_session || rs.empty()) {
4949 _session->begin_reversible_command (_("toggle region lock"));
4951 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4952 (*i)->region()->clear_changes ();
4953 (*i)->region()->set_locked (!(*i)->region()->locked());
4954 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4957 _session->commit_reversible_command ();
4961 Editor::toggle_region_lock_style ()
4963 if (_ignore_region_action) {
4967 RegionSelection rs = get_regions_from_selection_and_entered ();
4969 if (!_session || rs.empty()) {
4973 _session->begin_reversible_command (_("region lock style"));
4975 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4976 (*i)->region()->clear_changes ();
4977 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
4978 (*i)->region()->set_position_lock_style (ns);
4979 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4982 _session->commit_reversible_command ();
4986 Editor::toggle_opaque_region ()
4988 if (_ignore_region_action) {
4992 RegionSelection rs = get_regions_from_selection_and_entered ();
4994 if (!_session || rs.empty()) {
4998 _session->begin_reversible_command (_("change region opacity"));
5000 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5001 (*i)->region()->clear_changes ();
5002 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5003 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5006 _session->commit_reversible_command ();
5010 Editor::toggle_record_enable ()
5012 bool new_state = false;
5014 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5015 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5018 if (!rtav->is_track())
5022 new_state = !rtav->track()->record_enabled();
5026 rtav->track()->set_record_enabled (new_state, this);
5031 Editor::toggle_solo ()
5033 bool new_state = false;
5035 boost::shared_ptr<RouteList> rl (new RouteList);
5037 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5038 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5045 new_state = !rtav->route()->soloed ();
5049 rl->push_back (rtav->route());
5052 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5056 Editor::toggle_mute ()
5058 bool new_state = false;
5060 boost::shared_ptr<RouteList> rl (new RouteList);
5062 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5063 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5070 new_state = !rtav->route()->muted();
5074 rl->push_back (rtav->route());
5077 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5081 Editor::toggle_solo_isolate ()
5086 Editor::set_fade_length (bool in)
5088 RegionSelection rs = get_regions_from_selection_and_entered ();
5094 /* we need a region to measure the offset from the start */
5096 RegionView* rv = rs.front ();
5098 framepos_t pos = get_preferred_edit_position();
5102 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5103 /* edit point is outside the relevant region */
5108 if (pos <= rv->region()->position()) {
5112 len = pos - rv->region()->position();
5113 cmd = _("set fade in length");
5115 if (pos >= rv->region()->last_frame()) {
5119 len = rv->region()->last_frame() - pos;
5120 cmd = _("set fade out length");
5123 begin_reversible_command (cmd);
5125 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5126 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5132 boost::shared_ptr<AutomationList> alist;
5134 alist = tmp->audio_region()->fade_in();
5136 alist = tmp->audio_region()->fade_out();
5139 XMLNode &before = alist->get_state();
5142 tmp->audio_region()->set_fade_in_length (len);
5143 tmp->audio_region()->set_fade_in_active (true);
5145 tmp->audio_region()->set_fade_out_length (len);
5146 tmp->audio_region()->set_fade_out_active (true);
5149 XMLNode &after = alist->get_state();
5150 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5153 commit_reversible_command ();
5157 Editor::set_fade_in_shape (FadeShape shape)
5159 RegionSelection rs = get_regions_from_selection_and_entered ();
5165 begin_reversible_command (_("set fade in shape"));
5167 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5168 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5174 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5175 XMLNode &before = alist->get_state();
5177 tmp->audio_region()->set_fade_in_shape (shape);
5179 XMLNode &after = alist->get_state();
5180 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5183 commit_reversible_command ();
5188 Editor::set_fade_out_shape (FadeShape shape)
5190 RegionSelection rs = get_regions_from_selection_and_entered ();
5196 begin_reversible_command (_("set fade out shape"));
5198 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5199 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5205 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5206 XMLNode &before = alist->get_state();
5208 tmp->audio_region()->set_fade_out_shape (shape);
5210 XMLNode &after = alist->get_state();
5211 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5214 commit_reversible_command ();
5218 Editor::set_fade_in_active (bool yn)
5220 RegionSelection rs = get_regions_from_selection_and_entered ();
5226 begin_reversible_command (_("set fade in active"));
5228 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5229 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5236 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5238 ar->clear_changes ();
5239 ar->set_fade_in_active (yn);
5240 _session->add_command (new StatefulDiffCommand (ar));
5243 commit_reversible_command ();
5247 Editor::set_fade_out_active (bool yn)
5249 RegionSelection rs = get_regions_from_selection_and_entered ();
5255 begin_reversible_command (_("set fade out active"));
5257 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5258 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5264 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5266 ar->clear_changes ();
5267 ar->set_fade_out_active (yn);
5268 _session->add_command(new StatefulDiffCommand (ar));
5271 commit_reversible_command ();
5275 Editor::toggle_region_fades (int dir)
5277 if (_ignore_region_action) {
5281 boost::shared_ptr<AudioRegion> ar;
5284 RegionSelection rs = get_regions_from_selection_and_entered ();
5290 RegionSelection::iterator i;
5291 for (i = rs.begin(); i != rs.end(); ++i) {
5292 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5294 yn = ar->fade_out_active ();
5296 yn = ar->fade_in_active ();
5302 if (i == rs.end()) {
5306 /* XXX should this undo-able? */
5308 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5309 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5312 if (dir == 1 || dir == 0) {
5313 ar->set_fade_in_active (!yn);
5316 if (dir == -1 || dir == 0) {
5317 ar->set_fade_out_active (!yn);
5323 /** Update region fade visibility after its configuration has been changed */
5325 Editor::update_region_fade_visibility ()
5327 bool _fade_visibility = _session->config.get_show_region_fades ();
5329 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5330 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5332 if (_fade_visibility) {
5333 v->audio_view()->show_all_fades ();
5335 v->audio_view()->hide_all_fades ();
5342 Editor::set_edit_point ()
5347 if (!mouse_frame (where, ignored)) {
5353 if (selection->markers.empty()) {
5355 mouse_add_new_marker (where);
5360 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5363 loc->move_to (where);
5369 Editor::set_playhead_cursor ()
5371 if (entered_marker) {
5372 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5377 if (!mouse_frame (where, ignored)) {
5384 _session->request_locate (where, _session->transport_rolling());
5390 Editor::split_region ()
5392 if (((mouse_mode == MouseRange) ||
5393 (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) &&
5394 !selection->time.empty()) {
5395 separate_regions_between (selection->time);
5399 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5401 framepos_t where = get_preferred_edit_position ();
5407 split_regions_at (where, rs);
5410 struct EditorOrderRouteSorter {
5411 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5412 return a->order_key (EditorSort) < b->order_key (EditorSort);
5417 Editor::select_next_route()
5419 if (selection->tracks.empty()) {
5420 selection->set (track_views.front());
5424 TimeAxisView* current = selection->tracks.front();
5428 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5429 if (*i == current) {
5431 if (i != track_views.end()) {
5434 current = (*(track_views.begin()));
5435 //selection->set (*(track_views.begin()));
5440 rui = dynamic_cast<RouteUI *>(current);
5441 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5443 selection->set(current);
5445 ensure_track_visible(current);
5449 Editor::select_prev_route()
5451 if (selection->tracks.empty()) {
5452 selection->set (track_views.front());
5456 TimeAxisView* current = selection->tracks.front();
5460 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5461 if (*i == current) {
5463 if (i != track_views.rend()) {
5466 current = *(track_views.rbegin());
5471 rui = dynamic_cast<RouteUI *>(current);
5472 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5474 selection->set (current);
5476 ensure_track_visible(current);
5480 Editor::ensure_track_visible(TimeAxisView *track)
5482 if (track->hidden())
5485 double const current_view_min_y = vertical_adjustment.get_value();
5486 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5488 double const track_min_y = track->y_position ();
5489 double const track_max_y = track->y_position () + track->effective_height ();
5491 if (track_min_y >= current_view_min_y &&
5492 track_max_y <= current_view_max_y) {
5498 if (track_min_y < current_view_min_y) {
5499 // Track is above the current view
5500 new_value = track_min_y;
5502 // Track is below the current view
5503 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5506 vertical_adjustment.set_value(new_value);
5510 Editor::set_loop_from_selection (bool play)
5512 if (_session == 0 || selection->time.empty()) {
5516 framepos_t start = selection->time[clicked_selection].start;
5517 framepos_t end = selection->time[clicked_selection].end;
5519 set_loop_range (start, end, _("set loop range from selection"));
5522 _session->request_play_loop (true);
5523 _session->request_locate (start, true);
5528 Editor::set_loop_from_edit_range (bool play)
5530 if (_session == 0) {
5537 if (!get_edit_op_range (start, end)) {
5541 set_loop_range (start, end, _("set loop range from edit range"));
5544 _session->request_play_loop (true);
5545 _session->request_locate (start, true);
5550 Editor::set_loop_from_region (bool play)
5552 framepos_t start = max_framepos;
5555 RegionSelection rs = get_regions_from_selection_and_entered ();
5561 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5562 if ((*i)->region()->position() < start) {
5563 start = (*i)->region()->position();
5565 if ((*i)->region()->last_frame() + 1 > end) {
5566 end = (*i)->region()->last_frame() + 1;
5570 set_loop_range (start, end, _("set loop range from region"));
5573 _session->request_play_loop (true);
5574 _session->request_locate (start, true);
5579 Editor::set_punch_from_selection ()
5581 if (_session == 0 || selection->time.empty()) {
5585 framepos_t start = selection->time[clicked_selection].start;
5586 framepos_t end = selection->time[clicked_selection].end;
5588 set_punch_range (start, end, _("set punch range from selection"));
5592 Editor::set_punch_from_edit_range ()
5594 if (_session == 0) {
5601 if (!get_edit_op_range (start, end)) {
5605 set_punch_range (start, end, _("set punch range from edit range"));
5609 Editor::set_punch_from_region ()
5611 framepos_t start = max_framepos;
5614 RegionSelection rs = get_regions_from_selection_and_entered ();
5620 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5621 if ((*i)->region()->position() < start) {
5622 start = (*i)->region()->position();
5624 if ((*i)->region()->last_frame() + 1 > end) {
5625 end = (*i)->region()->last_frame() + 1;
5629 set_punch_range (start, end, _("set punch range from region"));
5633 Editor::pitch_shift_region ()
5635 RegionSelection rs = get_regions_from_selection_and_entered ();
5637 RegionSelection audio_rs;
5638 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5639 if (dynamic_cast<AudioRegionView*> (*i)) {
5640 audio_rs.push_back (*i);
5644 if (audio_rs.empty()) {
5648 pitch_shift (audio_rs, 1.2);
5652 Editor::transpose_region ()
5654 RegionSelection rs = get_regions_from_selection_and_entered ();
5656 list<MidiRegionView*> midi_region_views;
5657 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5658 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5660 midi_region_views.push_back (mrv);
5665 int const r = d.run ();
5666 if (r != RESPONSE_ACCEPT) {
5670 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5671 (*i)->midi_region()->transpose (d.semitones ());
5676 Editor::set_tempo_from_region ()
5678 RegionSelection rs = get_regions_from_selection_and_entered ();
5680 if (!_session || rs.empty()) {
5684 RegionView* rv = rs.front();
5686 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5690 Editor::use_range_as_bar ()
5692 framepos_t start, end;
5693 if (get_edit_op_range (start, end)) {
5694 define_one_bar (start, end);
5699 Editor::define_one_bar (framepos_t start, framepos_t end)
5701 framepos_t length = end - start;
5703 const Meter& m (_session->tempo_map().meter_at (start));
5705 /* length = 1 bar */
5707 /* now we want frames per beat.
5708 we have frames per bar, and beats per bar, so ...
5711 /* XXXX METER MATH */
5713 double frames_per_beat = length / m.divisions_per_bar();
5715 /* beats per minute = */
5717 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5719 /* now decide whether to:
5721 (a) set global tempo
5722 (b) add a new tempo marker
5726 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5728 bool do_global = false;
5730 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5732 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5733 at the start, or create a new marker
5736 vector<string> options;
5737 options.push_back (_("Cancel"));
5738 options.push_back (_("Add new marker"));
5739 options.push_back (_("Set global tempo"));
5742 _("Define one bar"),
5743 _("Do you want to set the global tempo or add a new tempo marker?"),
5747 c.set_default_response (2);
5763 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5764 if the marker is at the region starter, change it, otherwise add
5769 begin_reversible_command (_("set tempo from region"));
5770 XMLNode& before (_session->tempo_map().get_state());
5773 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5774 } else if (t.frame() == start) {
5775 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5777 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5780 XMLNode& after (_session->tempo_map().get_state());
5782 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5783 commit_reversible_command ();
5787 Editor::split_region_at_transients ()
5789 AnalysisFeatureList positions;
5791 RegionSelection rs = get_regions_from_selection_and_entered ();
5793 if (!_session || rs.empty()) {
5797 _session->begin_reversible_command (_("split regions"));
5799 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5801 RegionSelection::iterator tmp;
5806 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5808 if (ar && (ar->get_transients (positions) == 0)) {
5809 split_region_at_points ((*i)->region(), positions, true);
5816 _session->commit_reversible_command ();
5821 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5823 bool use_rhythmic_rodent = false;
5825 boost::shared_ptr<Playlist> pl = r->playlist();
5827 list<boost::shared_ptr<Region> > new_regions;
5833 if (positions.empty()) {
5838 if (positions.size() > 20 && can_ferret) {
5839 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);
5840 MessageDialog msg (msgstr,
5843 Gtk::BUTTONS_OK_CANCEL);
5846 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5847 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5849 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5852 msg.set_title (_("Excessive split?"));
5855 int response = msg.run();
5861 case RESPONSE_APPLY:
5862 use_rhythmic_rodent = true;
5869 if (use_rhythmic_rodent) {
5870 show_rhythm_ferret ();
5874 AnalysisFeatureList::const_iterator x;
5876 pl->clear_changes ();
5877 pl->clear_owned_changes ();
5879 x = positions.begin();
5881 if (x == positions.end()) {
5886 pl->remove_region (r);
5890 while (x != positions.end()) {
5892 /* deal with positons that are out of scope of present region bounds */
5893 if (*x <= 0 || *x > r->length()) {
5898 /* file start = original start + how far we from the initial position ?
5901 framepos_t file_start = r->start() + pos;
5903 /* length = next position - current position
5906 framepos_t len = (*x) - pos;
5908 /* XXX we do we really want to allow even single-sample regions?
5909 shouldn't we have some kind of lower limit on region size?
5918 if (RegionFactory::region_name (new_name, r->name())) {
5922 /* do NOT announce new regions 1 by one, just wait till they are all done */
5926 plist.add (ARDOUR::Properties::start, file_start);
5927 plist.add (ARDOUR::Properties::length, len);
5928 plist.add (ARDOUR::Properties::name, new_name);
5929 plist.add (ARDOUR::Properties::layer, 0);
5931 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5932 /* because we set annouce to false, manually add the new region to the
5935 RegionFactory::map_add (nr);
5937 pl->add_region (nr, r->position() + pos);
5940 new_regions.push_front(nr);
5949 RegionFactory::region_name (new_name, r->name());
5951 /* Add the final region */
5954 plist.add (ARDOUR::Properties::start, r->start() + pos);
5955 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
5956 plist.add (ARDOUR::Properties::name, new_name);
5957 plist.add (ARDOUR::Properties::layer, 0);
5959 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5960 /* because we set annouce to false, manually add the new region to the
5963 RegionFactory::map_add (nr);
5964 pl->add_region (nr, r->position() + pos);
5967 new_regions.push_front(nr);
5972 /* We might have removed regions, which alters other regions' layering_index,
5973 so we need to do a recursive diff here.
5975 vector<Command*> cmds;
5977 _session->add_commands (cmds);
5979 _session->add_command (new StatefulDiffCommand (pl));
5983 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
5984 set_selected_regionview_from_region_list ((*i), Selection::Add);
5990 Editor::place_transient()
5996 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6002 framepos_t where = get_preferred_edit_position();
6004 _session->begin_reversible_command (_("place transient"));
6006 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6007 framepos_t position = (*r)->region()->position();
6008 (*r)->region()->add_transient(where - position);
6011 _session->commit_reversible_command ();
6015 Editor::remove_transient(ArdourCanvas::Item* item)
6021 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6024 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6025 _arv->remove_transient (*(float*) _line->get_data ("position"));
6029 Editor::snap_regions_to_grid ()
6031 list <boost::shared_ptr<Playlist > > used_playlists;
6033 RegionSelection rs = get_regions_from_selection_and_entered ();
6035 if (!_session || rs.empty()) {
6039 _session->begin_reversible_command (_("snap regions to grid"));
6041 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6043 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6045 if (!pl->frozen()) {
6046 /* we haven't seen this playlist before */
6048 /* remember used playlists so we can thaw them later */
6049 used_playlists.push_back(pl);
6053 framepos_t start_frame = (*r)->region()->first_frame ();
6054 snap_to (start_frame);
6055 (*r)->region()->set_position (start_frame);
6058 while (used_playlists.size() > 0) {
6059 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6061 used_playlists.pop_front();
6064 _session->commit_reversible_command ();
6068 Editor::close_region_gaps ()
6070 list <boost::shared_ptr<Playlist > > used_playlists;
6072 RegionSelection rs = get_regions_from_selection_and_entered ();
6074 if (!_session || rs.empty()) {
6078 Dialog dialog (_("Close Region Gaps"));
6081 table.set_spacings (12);
6082 table.set_border_width (12);
6083 Label* l = manage (left_aligned_label (_("Crossfade length")));
6084 table.attach (*l, 0, 1, 0, 1);
6086 SpinButton spin_crossfade (1, 0);
6087 spin_crossfade.set_range (0, 15);
6088 spin_crossfade.set_increments (1, 1);
6089 spin_crossfade.set_value (5);
6090 table.attach (spin_crossfade, 1, 2, 0, 1);
6092 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6094 l = manage (left_aligned_label (_("Pull-back length")));
6095 table.attach (*l, 0, 1, 1, 2);
6097 SpinButton spin_pullback (1, 0);
6098 spin_pullback.set_range (0, 100);
6099 spin_pullback.set_increments (1, 1);
6100 spin_pullback.set_value(30);
6101 table.attach (spin_pullback, 1, 2, 1, 2);
6103 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6105 dialog.get_vbox()->pack_start (table);
6106 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6107 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6110 if (dialog.run () == RESPONSE_CANCEL) {
6114 framepos_t crossfade_len = spin_crossfade.get_value();
6115 framepos_t pull_back_frames = spin_pullback.get_value();
6117 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6118 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6120 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6122 _session->begin_reversible_command (_("close region gaps"));
6125 boost::shared_ptr<Region> last_region;
6127 rs.sort_by_position_and_track();
6129 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6131 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6133 if (!pl->frozen()) {
6134 /* we haven't seen this playlist before */
6136 /* remember used playlists so we can thaw them later */
6137 used_playlists.push_back(pl);
6141 framepos_t position = (*r)->region()->position();
6143 if (idx == 0 || position < last_region->position()){
6144 last_region = (*r)->region();
6149 (*r)->region()->trim_front( (position - pull_back_frames));
6150 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6152 last_region = (*r)->region();
6157 while (used_playlists.size() > 0) {
6158 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6160 used_playlists.pop_front();
6163 _session->commit_reversible_command ();
6167 Editor::tab_to_transient (bool forward)
6169 AnalysisFeatureList positions;
6171 RegionSelection rs = get_regions_from_selection_and_entered ();
6177 framepos_t pos = _session->audible_frame ();
6179 if (!selection->tracks.empty()) {
6181 /* don't waste time searching for transients in duplicate playlists.
6184 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6186 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6188 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6191 boost::shared_ptr<Track> tr = rtv->track();
6193 boost::shared_ptr<Playlist> pl = tr->playlist ();
6195 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6198 positions.push_back (result);
6211 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6212 (*r)->region()->get_transients (positions);
6216 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6219 AnalysisFeatureList::iterator x;
6221 for (x = positions.begin(); x != positions.end(); ++x) {
6227 if (x != positions.end ()) {
6228 _session->request_locate (*x);
6232 AnalysisFeatureList::reverse_iterator x;
6234 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6240 if (x != positions.rend ()) {
6241 _session->request_locate (*x);
6247 Editor::playhead_forward_to_grid ()
6249 if (!_session) return;
6250 framepos_t pos = playhead_cursor->current_frame;
6251 if (pos < max_framepos - 1) {
6253 snap_to_internal (pos, 1, false);
6254 _session->request_locate (pos);
6260 Editor::playhead_backward_to_grid ()
6262 if (!_session) return;
6263 framepos_t pos = playhead_cursor->current_frame;
6266 snap_to_internal (pos, -1, false);
6267 _session->request_locate (pos);
6272 Editor::set_track_height (Height h)
6274 TrackSelection& ts (selection->tracks);
6276 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6277 (*x)->set_height_enum (h);
6282 Editor::toggle_tracks_active ()
6284 TrackSelection& ts (selection->tracks);
6286 bool target = false;
6292 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6293 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6297 target = !rtv->_route->active();
6300 rtv->_route->set_active (target, this);
6306 Editor::remove_tracks ()
6308 TrackSelection& ts (selection->tracks);
6314 vector<string> choices;
6318 const char* trackstr;
6320 vector<boost::shared_ptr<Route> > routes;
6321 bool special_bus = false;
6323 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6324 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6326 if (rtv->is_track()) {
6332 routes.push_back (rtv->_route);
6334 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6339 if (special_bus && !Config->get_allow_special_bus_removal()) {
6340 MessageDialog msg (_("That would be bad news ...."),
6344 msg.set_secondary_text (string_compose (_(
6345 "Removing the master or monitor bus is such a bad idea\n\
6346 that %1 is not going to allow it.\n\
6348 If you really want to do this sort of thing\n\
6349 edit your ardour.rc file to set the\n\
6350 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6357 if (ntracks + nbusses == 0) {
6362 trackstr = _("tracks");
6364 trackstr = _("track");
6368 busstr = _("busses");
6375 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6376 "(You may also lose the playlists associated with the %2)\n\n"
6377 "This action cannot be undone, and the session file will be overwritten!"),
6378 ntracks, trackstr, nbusses, busstr);
6380 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6381 "(You may also lose the playlists associated with the %2)\n\n"
6382 "This action cannot be undone, and the session file will be overwritten!"),
6385 } else if (nbusses) {
6386 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6387 "This action cannot be undon, and the session file will be overwritten"),
6391 choices.push_back (_("No, do nothing."));
6392 if (ntracks + nbusses > 1) {
6393 choices.push_back (_("Yes, remove them."));
6395 choices.push_back (_("Yes, remove it."));
6400 title = string_compose (_("Remove %1"), trackstr);
6402 title = string_compose (_("Remove %1"), busstr);
6405 Choice prompter (title, prompt, choices);
6407 if (prompter.run () != 1) {
6411 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6412 _session->remove_route (*x);
6417 Editor::do_insert_time ()
6419 if (selection->tracks.empty()) {
6423 InsertTimeDialog d (*this);
6424 int response = d.run ();
6426 if (response != RESPONSE_OK) {
6430 if (d.distance() == 0) {
6434 InsertTimeOption opt = d.intersected_region_action ();
6437 get_preferred_edit_position(),
6443 d.move_glued_markers(),
6444 d.move_locked_markers(),
6450 Editor::insert_time (
6451 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6452 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6455 bool commit = false;
6457 if (Config->get_edit_mode() == Lock) {
6461 begin_reversible_command (_("insert time"));
6463 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6465 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6469 /* don't operate on any playlist more than once, which could
6470 * happen if "all playlists" is enabled, but there is more
6471 * than 1 track using playlists "from" a given track.
6474 set<boost::shared_ptr<Playlist> > pl;
6476 if (all_playlists) {
6477 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6479 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6480 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6485 if ((*x)->playlist ()) {
6486 pl.insert ((*x)->playlist ());
6490 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6492 (*i)->clear_changes ();
6493 (*i)->clear_owned_changes ();
6495 if (opt == SplitIntersected) {
6499 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6501 vector<Command*> cmds;
6503 _session->add_commands (cmds);
6505 _session->add_command (new StatefulDiffCommand (*i));
6510 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6512 rtav->route ()->shift (pos, frames);
6520 XMLNode& before (_session->locations()->get_state());
6521 Locations::LocationList copy (_session->locations()->list());
6523 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6525 Locations::LocationList::const_iterator tmp;
6527 bool const was_locked = (*i)->locked ();
6528 if (locked_markers_too) {
6532 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6534 if ((*i)->start() >= pos) {
6535 (*i)->set_start ((*i)->start() + frames);
6536 if (!(*i)->is_mark()) {
6537 (*i)->set_end ((*i)->end() + frames);
6550 XMLNode& after (_session->locations()->get_state());
6551 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6556 _session->tempo_map().insert_time (pos, frames);
6560 commit_reversible_command ();
6565 Editor::fit_selected_tracks ()
6567 if (!selection->tracks.empty()) {
6568 fit_tracks (selection->tracks);
6572 /* no selected tracks - use tracks with selected regions */
6574 if (!selection->regions.empty()) {
6575 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6576 tvl.push_back (&(*r)->get_time_axis_view ());
6582 } else if (internal_editing()) {
6583 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6586 if (entered_track) {
6587 tvl.push_back (entered_track);
6595 Editor::fit_tracks (TrackViewList & tracks)
6597 if (tracks.empty()) {
6601 uint32_t child_heights = 0;
6602 int visible_tracks = 0;
6604 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6606 if (!(*t)->marked_for_display()) {
6610 child_heights += (*t)->effective_height() - (*t)->current_height();
6614 uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / visible_tracks);
6615 double first_y_pos = DBL_MAX;
6617 if (h < TimeAxisView::preset_height (HeightSmall)) {
6618 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6619 /* too small to be displayed */
6623 undo_visual_stack.push_back (current_visual_state (true));
6624 no_save_visual = true;
6626 /* build a list of all tracks, including children */
6629 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6631 TimeAxisView::Children c = (*i)->get_child_list ();
6632 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6633 all.push_back (j->get());
6637 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6639 bool prev_was_selected = false;
6640 bool is_selected = tracks.contains (all.front());
6641 bool next_is_selected;
6643 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6645 TrackViewList::iterator next;
6650 if (next != all.end()) {
6651 next_is_selected = tracks.contains (*next);
6653 next_is_selected = false;
6656 if ((*t)->marked_for_display ()) {
6658 (*t)->set_height (h);
6659 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6661 if (prev_was_selected && next_is_selected) {
6662 hide_track_in_display (*t);
6667 prev_was_selected = is_selected;
6668 is_selected = next_is_selected;
6672 set the controls_layout height now, because waiting for its size
6673 request signal handler will cause the vertical adjustment setting to fail
6676 controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6677 vertical_adjustment.set_value (first_y_pos);
6679 redo_visual_stack.push_back (current_visual_state (true));
6683 Editor::save_visual_state (uint32_t n)
6685 while (visual_states.size() <= n) {
6686 visual_states.push_back (0);
6689 if (visual_states[n] != 0) {
6690 delete visual_states[n];
6693 visual_states[n] = current_visual_state (true);
6698 Editor::goto_visual_state (uint32_t n)
6700 if (visual_states.size() <= n) {
6704 if (visual_states[n] == 0) {
6708 use_visual_state (*visual_states[n]);
6712 Editor::start_visual_state_op (uint32_t n)
6714 save_visual_state (n);
6716 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6718 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6719 pup->set_text (buf);
6724 Editor::cancel_visual_state_op (uint32_t n)
6726 goto_visual_state (n);
6730 Editor::toggle_region_mute ()
6732 if (_ignore_region_action) {
6736 RegionSelection rs = get_regions_from_selection_and_entered ();
6742 if (rs.size() > 1) {
6743 begin_reversible_command (_("mute regions"));
6745 begin_reversible_command (_("mute region"));
6748 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6750 (*i)->region()->playlist()->clear_changes ();
6751 (*i)->region()->set_muted (!(*i)->region()->muted ());
6752 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6756 commit_reversible_command ();
6760 Editor::combine_regions ()
6762 /* foreach track with selected regions, take all selected regions
6763 and join them into a new region containing the subregions (as a
6767 typedef set<RouteTimeAxisView*> RTVS;
6770 if (selection->regions.empty()) {
6774 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6775 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6778 tracks.insert (rtv);
6782 begin_reversible_command (_("combine regions"));
6784 vector<RegionView*> new_selection;
6786 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6789 if ((rv = (*i)->combine_regions ()) != 0) {
6790 new_selection.push_back (rv);
6794 selection->clear_regions ();
6795 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6796 selection->add (*i);
6799 commit_reversible_command ();
6803 Editor::uncombine_regions ()
6805 typedef set<RouteTimeAxisView*> RTVS;
6808 if (selection->regions.empty()) {
6812 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6813 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6816 tracks.insert (rtv);
6820 begin_reversible_command (_("uncombine regions"));
6822 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6823 (*i)->uncombine_regions ();
6826 commit_reversible_command ();
6830 Editor::toggle_midi_input_active (bool flip_others)
6833 boost::shared_ptr<RouteList> rl (new RouteList);
6835 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6836 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6842 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6845 rl->push_back (rtav->route());
6846 onoff = !mt->input_active();
6850 _session->set_exclusive_input_active (rl, onoff, flip_others);