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/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
60 #include "ardour_ui.h"
63 #include "time_axis_view.h"
64 #include "route_time_axis.h"
65 #include "audio_time_axis.h"
66 #include "automation_time_axis.h"
67 #include "control_point.h"
68 #include "streamview.h"
69 #include "audio_streamview.h"
70 #include "audio_region_view.h"
71 #include "midi_region_view.h"
72 #include "rgb_macros.h"
73 #include "selection_templates.h"
74 #include "selection.h"
76 #include "gtk-custom-hruler.h"
77 #include "gui_thread.h"
80 #include "editor_drag.h"
81 #include "strip_silence_dialog.h"
82 #include "editor_routes.h"
83 #include "editor_regions.h"
84 #include "quantize_dialog.h"
85 #include "interthread_progress_window.h"
86 #include "insert_time_dialog.h"
87 #include "normalize_dialog.h"
88 #include "editor_cursors.h"
89 #include "mouse_cursors.h"
90 #include "patch_change_dialog.h"
91 #include "transpose_dialog.h"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
101 using Gtkmm2ext::Keyboard;
103 /***********************************************************************
105 ***********************************************************************/
108 Editor::undo (uint32_t n)
110 if (_drags->active ()) {
120 Editor::redo (uint32_t n)
122 if (_drags->active ()) {
132 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
136 list <boost::shared_ptr<Playlist > > used_playlists;
138 if (regions.empty()) {
142 begin_reversible_command (_("split"));
144 // if splitting a single region, and snap-to is using
145 // region boundaries, don't pay attention to them
147 if (regions.size() == 1) {
148 switch (_snap_type) {
149 case SnapToRegionStart:
150 case SnapToRegionSync:
151 case SnapToRegionEnd:
160 EditorFreeze(); /* Emit Signal */
163 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
165 RegionSelection::iterator tmp;
167 /* XXX this test needs to be more complicated, to make sure we really
168 have something to split.
171 if (!(*a)->region()->covers (where)) {
179 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
187 /* we haven't seen this playlist before */
189 /* remember used playlists so we can thaw them later */
190 used_playlists.push_back(pl);
195 pl->clear_changes ();
196 pl->split_region ((*a)->region(), where);
197 _session->add_command (new StatefulDiffCommand (pl));
203 while (used_playlists.size() > 0) {
204 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
206 used_playlists.pop_front();
209 commit_reversible_command ();
212 EditorThaw(); /* Emit Signal */
216 /** Move one extreme of the current range selection. If more than one range is selected,
217 * the start of the earliest range or the end of the latest range is moved.
219 * @param move_end true to move the end of the current range selection, false to move
221 * @param next true to move the extreme to the next region boundary, false to move to
225 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
227 if (selection->time.start() == selection->time.end_frame()) {
231 framepos_t start = selection->time.start ();
232 framepos_t end = selection->time.end_frame ();
234 /* the position of the thing we may move */
235 framepos_t pos = move_end ? end : start;
236 int dir = next ? 1 : -1;
238 /* so we don't find the current region again */
239 if (dir > 0 || pos > 0) {
243 framepos_t const target = get_region_boundary (pos, dir, true, false);
258 begin_reversible_command (_("alter selection"));
259 selection->set_preserving_all_ranges (start, end);
260 commit_reversible_command ();
264 Editor::nudge_forward_release (GdkEventButton* ev)
266 if (ev->state & Keyboard::PrimaryModifier) {
267 nudge_forward (false, true);
269 nudge_forward (false, false);
275 Editor::nudge_backward_release (GdkEventButton* ev)
277 if (ev->state & Keyboard::PrimaryModifier) {
278 nudge_backward (false, true);
280 nudge_backward (false, false);
287 Editor::nudge_forward (bool next, bool force_playhead)
290 framepos_t next_distance;
296 RegionSelection rs = get_regions_from_selection_and_entered ();
298 if (!force_playhead && !rs.empty()) {
300 begin_reversible_command (_("nudge regions forward"));
302 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
303 boost::shared_ptr<Region> r ((*i)->region());
305 distance = get_nudge_distance (r->position(), next_distance);
308 distance = next_distance;
312 r->set_position (r->position() + distance);
313 _session->add_command (new StatefulDiffCommand (r));
316 commit_reversible_command ();
319 } else if (!force_playhead && !selection->markers.empty()) {
323 begin_reversible_command (_("nudge location forward"));
325 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
327 Location* loc = find_location_from_marker ((*i), is_start);
331 XMLNode& before (loc->get_state());
334 distance = get_nudge_distance (loc->start(), next_distance);
336 distance = next_distance;
338 if (max_framepos - distance > loc->start() + loc->length()) {
339 loc->set_start (loc->start() + distance);
341 loc->set_start (max_framepos - loc->length());
344 distance = get_nudge_distance (loc->end(), next_distance);
346 distance = next_distance;
348 if (max_framepos - distance > loc->end()) {
349 loc->set_end (loc->end() + distance);
351 loc->set_end (max_framepos);
354 XMLNode& after (loc->get_state());
355 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
359 commit_reversible_command ();
362 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
363 _session->request_locate (playhead_cursor->current_frame () + distance);
368 Editor::nudge_backward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions backward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
394 if (r->position() > distance) {
395 r->set_position (r->position() - distance);
399 _session->add_command (new StatefulDiffCommand (r));
402 commit_reversible_command ();
404 } else if (!force_playhead && !selection->markers.empty()) {
408 begin_reversible_command (_("nudge location forward"));
410 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
412 Location* loc = find_location_from_marker ((*i), is_start);
416 XMLNode& before (loc->get_state());
419 distance = get_nudge_distance (loc->start(), next_distance);
421 distance = next_distance;
423 if (distance < loc->start()) {
424 loc->set_start (loc->start() - distance);
429 distance = get_nudge_distance (loc->end(), next_distance);
432 distance = next_distance;
435 if (distance < loc->end() - loc->length()) {
436 loc->set_end (loc->end() - distance);
438 loc->set_end (loc->length());
442 XMLNode& after (loc->get_state());
443 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
447 commit_reversible_command ();
451 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
453 if (playhead_cursor->current_frame () > distance) {
454 _session->request_locate (playhead_cursor->current_frame () - distance);
456 _session->goto_start();
462 Editor::nudge_forward_capture_offset ()
464 RegionSelection rs = get_regions_from_selection_and_entered ();
466 if (!_session || rs.empty()) {
470 begin_reversible_command (_("nudge forward"));
472 framepos_t const distance = _session->worst_output_latency();
474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
475 boost::shared_ptr<Region> r ((*i)->region());
478 r->set_position (r->position() + distance);
479 _session->add_command(new StatefulDiffCommand (r));
482 commit_reversible_command ();
486 Editor::nudge_backward_capture_offset ()
488 RegionSelection rs = get_regions_from_selection_and_entered ();
490 if (!_session || rs.empty()) {
494 begin_reversible_command (_("nudge backward"));
496 framepos_t const distance = _session->worst_output_latency();
498 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
499 boost::shared_ptr<Region> r ((*i)->region());
503 if (r->position() > distance) {
504 r->set_position (r->position() - distance);
508 _session->add_command(new StatefulDiffCommand (r));
511 commit_reversible_command ();
517 Editor::move_to_start ()
519 _session->goto_start ();
523 Editor::move_to_end ()
526 _session->request_locate (_session->current_end_frame());
530 Editor::build_region_boundary_cache ()
533 vector<RegionPoint> interesting_points;
534 boost::shared_ptr<Region> r;
535 TrackViewList tracks;
538 region_boundary_cache.clear ();
544 switch (_snap_type) {
545 case SnapToRegionStart:
546 interesting_points.push_back (Start);
548 case SnapToRegionEnd:
549 interesting_points.push_back (End);
551 case SnapToRegionSync:
552 interesting_points.push_back (SyncPoint);
554 case SnapToRegionBoundary:
555 interesting_points.push_back (Start);
556 interesting_points.push_back (End);
559 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
564 TimeAxisView *ontrack = 0;
567 if (!selection->tracks.empty()) {
568 tlist = selection->tracks.filter_to_unique_playlists ();
570 tlist = track_views.filter_to_unique_playlists ();
573 while (pos < _session->current_end_frame() && !at_end) {
576 framepos_t lpos = max_framepos;
578 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
580 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
581 if (*p == interesting_points.back()) {
584 /* move to next point type */
590 rpos = r->first_frame();
594 rpos = r->last_frame();
598 rpos = r->sync_position ();
606 RouteTimeAxisView *rtav;
608 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
609 if (rtav->track() != 0) {
610 speed = rtav->track()->speed();
614 rpos = track_frame_to_session_frame (rpos, speed);
620 /* prevent duplicates, but we don't use set<> because we want to be able
624 vector<framepos_t>::iterator ri;
626 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
632 if (ri == region_boundary_cache.end()) {
633 region_boundary_cache.push_back (rpos);
640 /* finally sort to be sure that the order is correct */
642 sort (region_boundary_cache.begin(), region_boundary_cache.end());
645 boost::shared_ptr<Region>
646 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
648 TrackViewList::iterator i;
649 framepos_t closest = max_framepos;
650 boost::shared_ptr<Region> ret;
654 framepos_t track_frame;
655 RouteTimeAxisView *rtav;
657 for (i = tracks.begin(); i != tracks.end(); ++i) {
660 boost::shared_ptr<Region> r;
663 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
664 if (rtav->track()!=0)
665 track_speed = rtav->track()->speed();
668 track_frame = session_frame_to_track_frame(frame, track_speed);
670 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
676 rpos = r->first_frame ();
680 rpos = r->last_frame ();
684 rpos = r->sync_position ();
688 // rpos is a "track frame", converting it to "_session frame"
689 rpos = track_frame_to_session_frame(rpos, track_speed);
692 distance = rpos - frame;
694 distance = frame - rpos;
697 if (distance < closest) {
709 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
711 framecnt_t distance = max_framepos;
712 framepos_t current_nearest = -1;
714 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
715 framepos_t contender;
718 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
724 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
728 d = ::llabs (pos - contender);
731 current_nearest = contender;
736 return current_nearest;
740 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
745 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
747 if (!selection->tracks.empty()) {
749 target = find_next_region_boundary (pos, dir, selection->tracks);
753 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
754 get_onscreen_tracks (tvl);
755 target = find_next_region_boundary (pos, dir, tvl);
757 target = find_next_region_boundary (pos, dir, track_views);
763 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
764 get_onscreen_tracks (tvl);
765 target = find_next_region_boundary (pos, dir, tvl);
767 target = find_next_region_boundary (pos, dir, track_views);
775 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
777 framepos_t pos = playhead_cursor->current_frame ();
784 // so we don't find the current region again..
785 if (dir > 0 || pos > 0) {
789 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
793 _session->request_locate (target);
797 Editor::cursor_to_next_region_boundary (bool with_selection)
799 cursor_to_region_boundary (with_selection, 1);
803 Editor::cursor_to_previous_region_boundary (bool with_selection)
805 cursor_to_region_boundary (with_selection, -1);
809 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
811 boost::shared_ptr<Region> r;
812 framepos_t pos = cursor->current_frame ();
818 TimeAxisView *ontrack = 0;
820 // so we don't find the current region again..
824 if (!selection->tracks.empty()) {
826 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
828 } else if (clicked_axisview) {
831 t.push_back (clicked_axisview);
833 r = find_next_region (pos, point, dir, t, &ontrack);
837 r = find_next_region (pos, point, dir, track_views, &ontrack);
846 pos = r->first_frame ();
850 pos = r->last_frame ();
854 pos = r->sync_position ();
859 RouteTimeAxisView *rtav;
861 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
862 if (rtav->track() != 0) {
863 speed = rtav->track()->speed();
867 pos = track_frame_to_session_frame(pos, speed);
869 if (cursor == playhead_cursor) {
870 _session->request_locate (pos);
872 cursor->set_position (pos);
877 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
879 cursor_to_region_point (cursor, point, 1);
883 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
885 cursor_to_region_point (cursor, point, -1);
889 Editor::cursor_to_selection_start (EditorCursor *cursor)
893 switch (mouse_mode) {
895 if (!selection->regions.empty()) {
896 pos = selection->regions.start();
901 if (!selection->time.empty()) {
902 pos = selection->time.start ();
910 if (cursor == playhead_cursor) {
911 _session->request_locate (pos);
913 cursor->set_position (pos);
918 Editor::cursor_to_selection_end (EditorCursor *cursor)
922 switch (mouse_mode) {
924 if (!selection->regions.empty()) {
925 pos = selection->regions.end_frame();
930 if (!selection->time.empty()) {
931 pos = selection->time.end_frame ();
939 if (cursor == playhead_cursor) {
940 _session->request_locate (pos);
942 cursor->set_position (pos);
947 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
957 if (selection->markers.empty()) {
961 if (!mouse_frame (mouse, ignored)) {
965 add_location_mark (mouse);
968 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
972 framepos_t pos = loc->start();
974 // so we don't find the current region again..
975 if (dir > 0 || pos > 0) {
979 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
983 loc->move_to (target);
987 Editor::selected_marker_to_next_region_boundary (bool with_selection)
989 selected_marker_to_region_boundary (with_selection, 1);
993 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
995 selected_marker_to_region_boundary (with_selection, -1);
999 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1001 boost::shared_ptr<Region> r;
1006 if (!_session || selection->markers.empty()) {
1010 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1014 TimeAxisView *ontrack = 0;
1018 // so we don't find the current region again..
1022 if (!selection->tracks.empty()) {
1024 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1028 r = find_next_region (pos, point, dir, track_views, &ontrack);
1037 pos = r->first_frame ();
1041 pos = r->last_frame ();
1045 pos = r->adjust_to_sync (r->first_frame());
1050 RouteTimeAxisView *rtav;
1052 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1053 if (rtav->track() != 0) {
1054 speed = rtav->track()->speed();
1058 pos = track_frame_to_session_frame(pos, speed);
1064 Editor::selected_marker_to_next_region_point (RegionPoint point)
1066 selected_marker_to_region_point (point, 1);
1070 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1072 selected_marker_to_region_point (point, -1);
1076 Editor::selected_marker_to_selection_start ()
1082 if (!_session || selection->markers.empty()) {
1086 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1090 switch (mouse_mode) {
1092 if (!selection->regions.empty()) {
1093 pos = selection->regions.start();
1098 if (!selection->time.empty()) {
1099 pos = selection->time.start ();
1111 Editor::selected_marker_to_selection_end ()
1117 if (!_session || selection->markers.empty()) {
1121 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1125 switch (mouse_mode) {
1127 if (!selection->regions.empty()) {
1128 pos = selection->regions.end_frame();
1133 if (!selection->time.empty()) {
1134 pos = selection->time.end_frame ();
1146 Editor::scroll_playhead (bool forward)
1148 framepos_t pos = playhead_cursor->current_frame ();
1149 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1152 if (pos == max_framepos) {
1156 if (pos < max_framepos - delta) {
1175 _session->request_locate (pos);
1179 Editor::cursor_align (bool playhead_to_edit)
1185 if (playhead_to_edit) {
1187 if (selection->markers.empty()) {
1191 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1194 /* move selected markers to playhead */
1196 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1199 Location* loc = find_location_from_marker (*i, ignored);
1201 if (loc->is_mark()) {
1202 loc->set_start (playhead_cursor->current_frame ());
1204 loc->set (playhead_cursor->current_frame (),
1205 playhead_cursor->current_frame () + loc->length());
1212 Editor::scroll_backward (float pages)
1214 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1215 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1218 if (leftmost_frame < cnt) {
1221 frame = leftmost_frame - cnt;
1224 reset_x_origin (frame);
1228 Editor::scroll_forward (float pages)
1230 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1231 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1234 if (max_framepos - cnt < leftmost_frame) {
1235 frame = max_framepos - cnt;
1237 frame = leftmost_frame + cnt;
1240 reset_x_origin (frame);
1244 Editor::scroll_tracks_down ()
1246 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1247 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1248 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1251 vertical_adjustment.set_value (vert_value);
1255 Editor::scroll_tracks_up ()
1257 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1261 Editor::scroll_tracks_down_line ()
1263 double vert_value = vertical_adjustment.get_value() + 60;
1265 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1266 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1269 vertical_adjustment.set_value (vert_value);
1273 Editor::scroll_tracks_up_line ()
1275 reset_y_origin (vertical_adjustment.get_value() - 60);
1281 Editor::tav_zoom_step (bool coarser)
1283 _routes->suspend_redisplay ();
1287 if (selection->tracks.empty()) {
1290 ts = &selection->tracks;
1293 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1294 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1295 tv->step_height (coarser);
1298 _routes->resume_redisplay ();
1302 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1304 _routes->suspend_redisplay ();
1308 if (selection->tracks.empty() || force_all) {
1311 ts = &selection->tracks;
1314 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1315 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1316 uint32_t h = tv->current_height ();
1321 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1326 tv->set_height (h + 5);
1330 _routes->resume_redisplay ();
1334 Editor::clamp_samples_per_pixel (double& fpp) const
1336 bool clamped = false;
1343 if (max_framepos / fpp < 800) {
1344 fpp = max_framepos / 800.0;
1352 Editor::temporal_zoom_step (bool coarser)
1354 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1356 double nfpp = samples_per_pixel;
1359 nfpp = min (9e6, nfpp * 1.61803399);
1361 nfpp = max (1.0, nfpp / 1.61803399);
1364 temporal_zoom (nfpp);
1368 Editor::temporal_zoom (double fpp)
1374 framepos_t current_page = current_page_samples();
1375 framepos_t current_leftmost = leftmost_frame;
1376 framepos_t current_rightmost;
1377 framepos_t current_center;
1378 framepos_t new_page_size;
1379 framepos_t half_page_size;
1380 framepos_t leftmost_after_zoom = 0;
1382 bool in_track_canvas;
1386 clamp_samples_per_pixel (fpp);
1387 if (fpp == samples_per_pixel) {
1393 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1394 // segfaults for lack of memory. If somebody decides this is not high enough I
1395 // believe it can be raisen to higher values but some limit must be in place.
1400 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1401 half_page_size = new_page_size / 2;
1403 switch (zoom_focus) {
1405 leftmost_after_zoom = current_leftmost;
1408 case ZoomFocusRight:
1409 current_rightmost = leftmost_frame + current_page;
1410 if (current_rightmost < new_page_size) {
1411 leftmost_after_zoom = 0;
1413 leftmost_after_zoom = current_rightmost - new_page_size;
1417 case ZoomFocusCenter:
1418 current_center = current_leftmost + (current_page/2);
1419 if (current_center < half_page_size) {
1420 leftmost_after_zoom = 0;
1422 leftmost_after_zoom = current_center - half_page_size;
1426 case ZoomFocusPlayhead:
1427 /* centre playhead */
1428 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1431 leftmost_after_zoom = 0;
1432 } else if (l > max_framepos) {
1433 leftmost_after_zoom = max_framepos - new_page_size;
1435 leftmost_after_zoom = (framepos_t) l;
1439 case ZoomFocusMouse:
1440 /* try to keep the mouse over the same point in the display */
1442 if (!mouse_frame (where, in_track_canvas)) {
1443 /* use playhead instead */
1444 where = playhead_cursor->current_frame ();
1446 if (where < half_page_size) {
1447 leftmost_after_zoom = 0;
1449 leftmost_after_zoom = where - half_page_size;
1454 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1457 leftmost_after_zoom = 0;
1458 } else if (l > max_framepos) {
1459 leftmost_after_zoom = max_framepos - new_page_size;
1461 leftmost_after_zoom = (framepos_t) l;
1468 /* try to keep the edit point in the same place */
1469 where = get_preferred_edit_position ();
1473 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1476 leftmost_after_zoom = 0;
1477 } else if (l > max_framepos) {
1478 leftmost_after_zoom = max_framepos - new_page_size;
1480 leftmost_after_zoom = (framepos_t) l;
1484 /* edit point not defined */
1491 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1493 reposition_and_zoom (leftmost_after_zoom, nfpp);
1497 Editor::temporal_zoom_region (bool both_axes)
1499 framepos_t start = max_framepos;
1501 set<TimeAxisView*> tracks;
1503 RegionSelection rs = get_regions_from_selection_and_entered ();
1509 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1511 if ((*i)->region()->position() < start) {
1512 start = (*i)->region()->position();
1515 if ((*i)->region()->last_frame() + 1 > end) {
1516 end = (*i)->region()->last_frame() + 1;
1519 tracks.insert (&((*i)->get_time_axis_view()));
1522 /* now comes an "interesting" hack ... make sure we leave a little space
1523 at each end of the editor so that the zoom doesn't fit the region
1524 precisely to the screen.
1527 GdkScreen* screen = gdk_screen_get_default ();
1528 gint pixwidth = gdk_screen_get_width (screen);
1529 gint mmwidth = gdk_screen_get_width_mm (screen);
1530 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1531 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1533 if ((start == 0 && end == 0) || end < start) {
1537 framepos_t range = end - start;
1538 double new_fpp = (double) range / (double) _visible_canvas_width;
1539 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1541 if (start > extra_samples) {
1542 start -= extra_samples;
1547 if (max_framepos - extra_samples > end) {
1548 end += extra_samples;
1553 /* if we're zooming on both axes we need to save track heights etc.
1556 undo_visual_stack.push_back (current_visual_state (both_axes));
1558 PBD::Unwinder<bool> nsv (no_save_visual, true);
1560 temporal_zoom_by_frame (start, end);
1563 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1565 /* set visible track heights appropriately */
1567 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1568 (*t)->set_height (per_track_height);
1571 /* hide irrelevant tracks */
1573 _routes->suspend_redisplay ();
1575 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1576 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1577 hide_track_in_display (*i);
1581 _routes->resume_redisplay ();
1583 vertical_adjustment.set_value (0.0);
1586 redo_visual_stack.push_back (current_visual_state (both_axes));
1590 Editor::zoom_to_region (bool both_axes)
1592 temporal_zoom_region (both_axes);
1596 Editor::temporal_zoom_selection ()
1598 if (!selection) return;
1600 if (selection->time.empty()) {
1604 framepos_t start = selection->time[clicked_selection].start;
1605 framepos_t end = selection->time[clicked_selection].end;
1607 temporal_zoom_by_frame (start, end);
1611 Editor::temporal_zoom_session ()
1613 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1616 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1617 double s = _session->current_start_frame() - l * 0.01;
1621 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1622 temporal_zoom_by_frame (framecnt_t (s), e);
1627 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1629 if (!_session) return;
1631 if ((start == 0 && end == 0) || end < start) {
1635 framepos_t range = end - start;
1637 double const new_fpp = (double) range / (double) _visible_canvas_width;
1639 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1640 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1641 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1643 if (new_leftmost > middle) {
1647 if (new_leftmost < 0) {
1651 reposition_and_zoom (new_leftmost, new_fpp);
1655 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1660 double range_before = frame - leftmost_frame;
1663 new_fpp = samples_per_pixel;
1666 new_fpp *= 1.61803399;
1667 range_before *= 1.61803399;
1669 new_fpp = max(1.0,(new_fpp/1.61803399));
1670 range_before /= 1.61803399;
1673 if (new_fpp == samples_per_pixel) {
1677 framepos_t new_leftmost = frame - (framepos_t)range_before;
1679 if (new_leftmost > frame) {
1683 if (new_leftmost < 0) {
1687 reposition_and_zoom (new_leftmost, new_fpp);
1692 Editor::choose_new_marker_name(string &name) {
1694 if (!Config->get_name_new_markers()) {
1695 /* don't prompt user for a new name */
1699 ArdourPrompter dialog (true);
1701 dialog.set_prompt (_("New Name:"));
1703 dialog.set_title (_("New Location Marker"));
1705 dialog.set_name ("MarkNameWindow");
1706 dialog.set_size_request (250, -1);
1707 dialog.set_position (Gtk::WIN_POS_MOUSE);
1709 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1710 dialog.set_initial_text (name);
1714 switch (dialog.run ()) {
1715 case RESPONSE_ACCEPT:
1721 dialog.get_result(name);
1728 Editor::add_location_from_selection ()
1732 if (selection->time.empty()) {
1736 if (_session == 0 || clicked_axisview == 0) {
1740 framepos_t start = selection->time[clicked_selection].start;
1741 framepos_t end = selection->time[clicked_selection].end;
1743 _session->locations()->next_available_name(rangename,"selection");
1744 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1746 _session->begin_reversible_command (_("add marker"));
1747 XMLNode &before = _session->locations()->get_state();
1748 _session->locations()->add (location, true);
1749 XMLNode &after = _session->locations()->get_state();
1750 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1751 _session->commit_reversible_command ();
1755 Editor::add_location_mark (framepos_t where)
1759 select_new_marker = true;
1761 _session->locations()->next_available_name(markername,"mark");
1762 if (!choose_new_marker_name(markername)) {
1765 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1766 _session->begin_reversible_command (_("add marker"));
1767 XMLNode &before = _session->locations()->get_state();
1768 _session->locations()->add (location, true);
1769 XMLNode &after = _session->locations()->get_state();
1770 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1771 _session->commit_reversible_command ();
1775 Editor::add_location_from_playhead_cursor ()
1777 add_location_mark (_session->audible_frame());
1780 /** Add a range marker around each selected region */
1782 Editor::add_locations_from_region ()
1784 RegionSelection rs = get_regions_from_selection_and_entered ();
1790 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1791 XMLNode &before = _session->locations()->get_state();
1793 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1795 boost::shared_ptr<Region> region = (*i)->region ();
1797 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1799 _session->locations()->add (location, true);
1802 XMLNode &after = _session->locations()->get_state();
1803 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1804 _session->commit_reversible_command ();
1807 /** Add a single range marker around all selected regions */
1809 Editor::add_location_from_region ()
1811 RegionSelection rs = get_regions_from_selection_and_entered ();
1817 _session->begin_reversible_command (_("add marker"));
1818 XMLNode &before = _session->locations()->get_state();
1822 if (rs.size() > 1) {
1823 _session->locations()->next_available_name(markername, "regions");
1825 RegionView* rv = *(rs.begin());
1826 boost::shared_ptr<Region> region = rv->region();
1827 markername = region->name();
1830 if (!choose_new_marker_name(markername)) {
1834 // single range spanning all selected
1835 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1836 _session->locations()->add (location, true);
1838 XMLNode &after = _session->locations()->get_state();
1839 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1840 _session->commit_reversible_command ();
1846 Editor::jump_forward_to_mark ()
1852 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
1858 _session->request_locate (pos, _session->transport_rolling());
1862 Editor::jump_backward_to_mark ()
1868 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
1874 _session->request_locate (pos, _session->transport_rolling());
1880 framepos_t const pos = _session->audible_frame ();
1883 _session->locations()->next_available_name (markername, "mark");
1885 if (!choose_new_marker_name (markername)) {
1889 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1893 Editor::clear_markers ()
1896 _session->begin_reversible_command (_("clear markers"));
1897 XMLNode &before = _session->locations()->get_state();
1898 _session->locations()->clear_markers ();
1899 XMLNode &after = _session->locations()->get_state();
1900 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1901 _session->commit_reversible_command ();
1906 Editor::clear_ranges ()
1909 _session->begin_reversible_command (_("clear ranges"));
1910 XMLNode &before = _session->locations()->get_state();
1912 Location * looploc = _session->locations()->auto_loop_location();
1913 Location * punchloc = _session->locations()->auto_punch_location();
1914 Location * sessionloc = _session->locations()->session_range_location();
1916 _session->locations()->clear_ranges ();
1918 if (looploc) _session->locations()->add (looploc);
1919 if (punchloc) _session->locations()->add (punchloc);
1920 if (sessionloc) _session->locations()->add (sessionloc);
1922 XMLNode &after = _session->locations()->get_state();
1923 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1924 _session->commit_reversible_command ();
1929 Editor::clear_locations ()
1931 _session->begin_reversible_command (_("clear locations"));
1932 XMLNode &before = _session->locations()->get_state();
1933 _session->locations()->clear ();
1934 XMLNode &after = _session->locations()->get_state();
1935 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1936 _session->commit_reversible_command ();
1937 _session->locations()->clear ();
1941 Editor::unhide_markers ()
1943 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1944 Location *l = (*i).first;
1945 if (l->is_hidden() && l->is_mark()) {
1946 l->set_hidden(false, this);
1952 Editor::unhide_ranges ()
1954 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1955 Location *l = (*i).first;
1956 if (l->is_hidden() && l->is_range_marker()) {
1957 l->set_hidden(false, this);
1962 /* INSERT/REPLACE */
1965 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1969 RouteTimeAxisView *rtv = 0;
1970 boost::shared_ptr<Playlist> playlist;
1973 event.type = GDK_BUTTON_RELEASE;
1977 where = window_event_frame (&event, &cx, &cy);
1979 if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) {
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)
2010 RouteTimeAxisView *dest_rtv = 0;
2011 RouteTimeAxisView *source_rtv = 0;
2014 event.type = GDK_BUTTON_RELEASE;
2018 window_event_frame (&event, &cx, &cy);
2020 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2021 if (tv.first == 0) {
2025 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2029 /* use this drag source to add underlay to a track. But we really don't care
2030 about the Route, only the view of the route, so find it first */
2031 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2032 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2036 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2037 dest_rtv->add_underlay(source_rtv->view());
2044 Editor::insert_region_list_selection (float times)
2046 RouteTimeAxisView *tv = 0;
2047 boost::shared_ptr<Playlist> playlist;
2049 if (clicked_routeview != 0) {
2050 tv = clicked_routeview;
2051 } else if (!selection->tracks.empty()) {
2052 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2055 } else if (entered_track != 0) {
2056 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2063 if ((playlist = tv->playlist()) == 0) {
2067 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2072 begin_reversible_command (_("insert region"));
2073 playlist->clear_changes ();
2074 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2075 _session->add_command(new StatefulDiffCommand (playlist));
2076 commit_reversible_command ();
2079 /* BUILT-IN EFFECTS */
2082 Editor::reverse_selection ()
2087 /* GAIN ENVELOPE EDITING */
2090 Editor::edit_envelope ()
2097 Editor::transition_to_rolling (bool fwd)
2103 if (_session->config.get_external_sync()) {
2104 switch (Config->get_sync_source()) {
2108 /* transport controlled by the master */
2113 if (_session->is_auditioning()) {
2114 _session->cancel_audition ();
2118 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2122 Editor::play_from_start ()
2124 _session->request_locate (_session->current_start_frame(), true);
2128 Editor::play_from_edit_point ()
2130 _session->request_locate (get_preferred_edit_position(), true);
2134 Editor::play_from_edit_point_and_return ()
2136 framepos_t start_frame;
2137 framepos_t return_frame;
2139 start_frame = get_preferred_edit_position (true);
2141 if (_session->transport_rolling()) {
2142 _session->request_locate (start_frame, false);
2146 /* don't reset the return frame if its already set */
2148 if ((return_frame = _session->requested_return_frame()) < 0) {
2149 return_frame = _session->audible_frame();
2152 if (start_frame >= 0) {
2153 _session->request_roll_at_and_return (start_frame, return_frame);
2158 Editor::play_selection ()
2160 if (selection->time.empty()) {
2164 _session->request_play_range (&selection->time, true);
2168 Editor::get_preroll ()
2170 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2175 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2177 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2180 location -= get_preroll();
2182 //don't try to locate before the beginning of time
2186 //if follow_playhead is on, keep the playhead on the screen
2187 if ( _follow_playhead )
2188 if ( location < leftmost_frame )
2189 location = leftmost_frame;
2191 _session->request_locate( location );
2195 Editor::play_with_preroll ()
2197 if (selection->time.empty()) {
2200 framepos_t preroll = get_preroll();
2202 framepos_t start = 0;
2203 if (selection->time[clicked_selection].start > preroll)
2204 start = selection->time[clicked_selection].start - preroll;
2206 framepos_t end = selection->time[clicked_selection].end + preroll;
2208 AudioRange ar (start, end, 0);
2209 list<AudioRange> lar;
2212 _session->request_play_range (&lar, true);
2217 Editor::play_location (Location& location)
2219 if (location.start() <= location.end()) {
2223 _session->request_bounded_roll (location.start(), location.end());
2227 Editor::loop_location (Location& location)
2229 if (location.start() <= location.end()) {
2235 if ((tll = transport_loop_location()) != 0) {
2236 tll->set (location.start(), location.end());
2238 // enable looping, reposition and start rolling
2239 _session->request_play_loop (true);
2240 _session->request_locate (tll->start(), true);
2245 Editor::do_layer_operation (LayerOperation op)
2247 if (selection->regions.empty ()) {
2251 bool const multiple = selection->regions.size() > 1;
2255 begin_reversible_command (_("raise regions"));
2257 begin_reversible_command (_("raise region"));
2263 begin_reversible_command (_("raise regions to top"));
2265 begin_reversible_command (_("raise region to top"));
2271 begin_reversible_command (_("lower regions"));
2273 begin_reversible_command (_("lower region"));
2279 begin_reversible_command (_("lower regions to bottom"));
2281 begin_reversible_command (_("lower region"));
2286 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2287 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2288 (*i)->clear_owned_changes ();
2291 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2292 boost::shared_ptr<Region> r = (*i)->region ();
2304 r->lower_to_bottom ();
2308 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2309 vector<Command*> cmds;
2311 _session->add_commands (cmds);
2314 commit_reversible_command ();
2318 Editor::raise_region ()
2320 do_layer_operation (Raise);
2324 Editor::raise_region_to_top ()
2326 do_layer_operation (RaiseToTop);
2330 Editor::lower_region ()
2332 do_layer_operation (Lower);
2336 Editor::lower_region_to_bottom ()
2338 do_layer_operation (LowerToBottom);
2341 /** Show the region editor for the selected regions */
2343 Editor::show_region_properties ()
2345 selection->foreach_regionview (&RegionView::show_region_editor);
2348 /** Show the midi list editor for the selected MIDI regions */
2350 Editor::show_midi_list_editor ()
2352 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2356 Editor::rename_region ()
2358 RegionSelection rs = get_regions_from_selection_and_entered ();
2364 ArdourDialog d (*this, _("Rename Region"), true, false);
2366 Label label (_("New name:"));
2369 hbox.set_spacing (6);
2370 hbox.pack_start (label, false, false);
2371 hbox.pack_start (entry, true, true);
2373 d.get_vbox()->set_border_width (12);
2374 d.get_vbox()->pack_start (hbox, false, false);
2376 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2377 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2379 d.set_size_request (300, -1);
2380 d.set_position (Gtk::WIN_POS_MOUSE);
2382 entry.set_text (rs.front()->region()->name());
2383 entry.select_region (0, -1);
2385 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2391 int const ret = d.run();
2395 if (ret != RESPONSE_OK) {
2399 std::string str = entry.get_text();
2400 strip_whitespace_edges (str);
2402 rs.front()->region()->set_name (str);
2403 _regions->redisplay ();
2408 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2410 if (_session->is_auditioning()) {
2411 _session->cancel_audition ();
2414 // note: some potential for creativity here, because region doesn't
2415 // have to belong to the playlist that Route is handling
2417 // bool was_soloed = route.soloed();
2419 route.set_solo (true, this);
2421 _session->request_bounded_roll (region->position(), region->position() + region->length());
2423 /* XXX how to unset the solo state ? */
2426 /** Start an audition of the first selected region */
2428 Editor::play_edit_range ()
2430 framepos_t start, end;
2432 if (get_edit_op_range (start, end)) {
2433 _session->request_bounded_roll (start, end);
2438 Editor::play_selected_region ()
2440 framepos_t start = max_framepos;
2443 RegionSelection rs = get_regions_from_selection_and_entered ();
2449 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2450 if ((*i)->region()->position() < start) {
2451 start = (*i)->region()->position();
2453 if ((*i)->region()->last_frame() + 1 > end) {
2454 end = (*i)->region()->last_frame() + 1;
2458 _session->request_bounded_roll (start, end);
2462 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2464 _session->audition_region (region);
2468 Editor::region_from_selection ()
2470 if (clicked_axisview == 0) {
2474 if (selection->time.empty()) {
2478 framepos_t start = selection->time[clicked_selection].start;
2479 framepos_t end = selection->time[clicked_selection].end;
2481 TrackViewList tracks = get_tracks_for_range_action ();
2483 framepos_t selection_cnt = end - start + 1;
2485 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2486 boost::shared_ptr<Region> current;
2487 boost::shared_ptr<Playlist> pl;
2488 framepos_t internal_start;
2491 if ((pl = (*i)->playlist()) == 0) {
2495 if ((current = pl->top_region_at (start)) == 0) {
2499 internal_start = start - current->position();
2500 RegionFactory::region_name (new_name, current->name(), true);
2504 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2505 plist.add (ARDOUR::Properties::length, selection_cnt);
2506 plist.add (ARDOUR::Properties::name, new_name);
2507 plist.add (ARDOUR::Properties::layer, 0);
2509 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2514 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2516 if (selection->time.empty() || selection->tracks.empty()) {
2520 framepos_t start = selection->time[clicked_selection].start;
2521 framepos_t end = selection->time[clicked_selection].end;
2523 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2524 sort_track_selection (ts);
2526 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2527 boost::shared_ptr<Region> current;
2528 boost::shared_ptr<Playlist> playlist;
2529 framepos_t internal_start;
2532 if ((playlist = (*i)->playlist()) == 0) {
2536 if ((current = playlist->top_region_at(start)) == 0) {
2540 internal_start = start - current->position();
2541 RegionFactory::region_name (new_name, current->name(), true);
2545 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2546 plist.add (ARDOUR::Properties::length, end - start + 1);
2547 plist.add (ARDOUR::Properties::name, new_name);
2549 new_regions.push_back (RegionFactory::create (current, plist));
2554 Editor::split_multichannel_region ()
2556 RegionSelection rs = get_regions_from_selection_and_entered ();
2562 vector< boost::shared_ptr<Region> > v;
2564 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2565 (*x)->region()->separate_by_channel (*_session, v);
2570 Editor::new_region_from_selection ()
2572 region_from_selection ();
2573 cancel_selection ();
2577 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2579 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2580 case Evoral::OverlapNone:
2588 * - selected tracks, or if there are none...
2589 * - tracks containing selected regions, or if there are none...
2594 Editor::get_tracks_for_range_action () const
2598 if (selection->tracks.empty()) {
2600 /* use tracks with selected regions */
2602 RegionSelection rs = selection->regions;
2604 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2605 TimeAxisView* tv = &(*i)->get_time_axis_view();
2607 if (!t.contains (tv)) {
2613 /* no regions and no tracks: use all tracks */
2619 t = selection->tracks;
2622 return t.filter_to_unique_playlists();
2626 Editor::separate_regions_between (const TimeSelection& ts)
2628 bool in_command = false;
2629 boost::shared_ptr<Playlist> playlist;
2630 RegionSelection new_selection;
2632 TrackViewList tmptracks = get_tracks_for_range_action ();
2633 sort_track_selection (tmptracks);
2635 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2637 RouteTimeAxisView* rtv;
2639 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2641 if (rtv->is_track()) {
2643 /* no edits to destructive tracks */
2645 if (rtv->track()->destructive()) {
2649 if ((playlist = rtv->playlist()) != 0) {
2651 playlist->clear_changes ();
2653 /* XXX need to consider musical time selections here at some point */
2655 double speed = rtv->track()->speed();
2658 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2660 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2661 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2663 latest_regionviews.clear ();
2665 playlist->partition ((framepos_t)((*t).start * speed),
2666 (framepos_t)((*t).end * speed), false);
2670 if (!latest_regionviews.empty()) {
2672 rtv->view()->foreach_regionview (sigc::bind (
2673 sigc::ptr_fun (add_if_covered),
2674 &(*t), &new_selection));
2677 begin_reversible_command (_("separate"));
2681 /* pick up changes to existing regions */
2683 vector<Command*> cmds;
2684 playlist->rdiff (cmds);
2685 _session->add_commands (cmds);
2687 /* pick up changes to the playlist itself (adds/removes)
2690 _session->add_command(new StatefulDiffCommand (playlist));
2699 selection->set (new_selection);
2700 set_mouse_mode (MouseObject);
2702 commit_reversible_command ();
2706 struct PlaylistState {
2707 boost::shared_ptr<Playlist> playlist;
2711 /** Take tracks from get_tracks_for_range_action and cut any regions
2712 * on those tracks so that the tracks are empty over the time
2716 Editor::separate_region_from_selection ()
2718 /* preferentially use *all* ranges in the time selection if we're in range mode
2719 to allow discontiguous operation, since get_edit_op_range() currently
2720 returns a single range.
2723 if (!selection->time.empty()) {
2725 separate_regions_between (selection->time);
2732 if (get_edit_op_range (start, end)) {
2734 AudioRange ar (start, end, 1);
2738 separate_regions_between (ts);
2744 Editor::separate_region_from_punch ()
2746 Location* loc = _session->locations()->auto_punch_location();
2748 separate_regions_using_location (*loc);
2753 Editor::separate_region_from_loop ()
2755 Location* loc = _session->locations()->auto_loop_location();
2757 separate_regions_using_location (*loc);
2762 Editor::separate_regions_using_location (Location& loc)
2764 if (loc.is_mark()) {
2768 AudioRange ar (loc.start(), loc.end(), 1);
2773 separate_regions_between (ts);
2776 /** Separate regions under the selected region */
2778 Editor::separate_under_selected_regions ()
2780 vector<PlaylistState> playlists;
2784 rs = get_regions_from_selection_and_entered();
2786 if (!_session || rs.empty()) {
2790 begin_reversible_command (_("separate region under"));
2792 list<boost::shared_ptr<Region> > regions_to_remove;
2794 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2795 // we can't just remove the region(s) in this loop because
2796 // this removes them from the RegionSelection, and they thus
2797 // disappear from underneath the iterator, and the ++i above
2798 // SEGVs in a puzzling fashion.
2800 // so, first iterate over the regions to be removed from rs and
2801 // add them to the regions_to_remove list, and then
2802 // iterate over the list to actually remove them.
2804 regions_to_remove.push_back ((*i)->region());
2807 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2809 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2812 // is this check necessary?
2816 vector<PlaylistState>::iterator i;
2818 //only take state if this is a new playlist.
2819 for (i = playlists.begin(); i != playlists.end(); ++i) {
2820 if ((*i).playlist == playlist) {
2825 if (i == playlists.end()) {
2827 PlaylistState before;
2828 before.playlist = playlist;
2829 before.before = &playlist->get_state();
2831 playlist->freeze ();
2832 playlists.push_back(before);
2835 //Partition on the region bounds
2836 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2838 //Re-add region that was just removed due to the partition operation
2839 playlist->add_region( (*rl), (*rl)->first_frame() );
2842 vector<PlaylistState>::iterator pl;
2844 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2845 (*pl).playlist->thaw ();
2846 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2849 commit_reversible_command ();
2853 Editor::crop_region_to_selection ()
2855 if (!selection->time.empty()) {
2857 crop_region_to (selection->time.start(), selection->time.end_frame());
2864 if (get_edit_op_range (start, end)) {
2865 crop_region_to (start, end);
2872 Editor::crop_region_to (framepos_t start, framepos_t end)
2874 vector<boost::shared_ptr<Playlist> > playlists;
2875 boost::shared_ptr<Playlist> playlist;
2878 if (selection->tracks.empty()) {
2879 ts = track_views.filter_to_unique_playlists();
2881 ts = selection->tracks.filter_to_unique_playlists ();
2884 sort_track_selection (ts);
2886 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2888 RouteTimeAxisView* rtv;
2890 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2892 boost::shared_ptr<Track> t = rtv->track();
2894 if (t != 0 && ! t->destructive()) {
2896 if ((playlist = rtv->playlist()) != 0) {
2897 playlists.push_back (playlist);
2903 if (playlists.empty()) {
2907 framepos_t the_start;
2911 begin_reversible_command (_("trim to selection"));
2913 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2915 boost::shared_ptr<Region> region;
2919 if ((region = (*i)->top_region_at(the_start)) == 0) {
2923 /* now adjust lengths to that we do the right thing
2924 if the selection extends beyond the region
2927 the_start = max (the_start, (framepos_t) region->position());
2928 if (max_framepos - the_start < region->length()) {
2929 the_end = the_start + region->length() - 1;
2931 the_end = max_framepos;
2933 the_end = min (end, the_end);
2934 cnt = the_end - the_start + 1;
2936 region->clear_changes ();
2937 region->trim_to (the_start, cnt);
2938 _session->add_command (new StatefulDiffCommand (region));
2941 commit_reversible_command ();
2945 Editor::region_fill_track ()
2947 RegionSelection rs = get_regions_from_selection_and_entered ();
2949 if (!_session || rs.empty()) {
2953 framepos_t const end = _session->current_end_frame ();
2955 begin_reversible_command (Operations::region_fill);
2957 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2959 boost::shared_ptr<Region> region ((*i)->region());
2961 boost::shared_ptr<Playlist> pl = region->playlist();
2963 if (end <= region->last_frame()) {
2967 double times = (double) (end - region->last_frame()) / (double) region->length();
2973 pl->clear_changes ();
2974 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2975 _session->add_command (new StatefulDiffCommand (pl));
2978 commit_reversible_command ();
2982 Editor::region_fill_selection ()
2984 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2988 if (selection->time.empty()) {
2992 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2997 framepos_t start = selection->time[clicked_selection].start;
2998 framepos_t end = selection->time[clicked_selection].end;
3000 boost::shared_ptr<Playlist> playlist;
3002 if (selection->tracks.empty()) {
3006 framepos_t selection_length = end - start;
3007 float times = (float)selection_length / region->length();
3009 begin_reversible_command (Operations::fill_selection);
3011 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3013 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3015 if ((playlist = (*i)->playlist()) == 0) {
3019 playlist->clear_changes ();
3020 playlist->add_region (RegionFactory::create (region, true), start, times);
3021 _session->add_command (new StatefulDiffCommand (playlist));
3024 commit_reversible_command ();
3028 Editor::set_region_sync_position ()
3030 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3034 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3036 bool in_command = false;
3038 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3040 if (!(*r)->region()->covers (where)) {
3044 boost::shared_ptr<Region> region ((*r)->region());
3047 begin_reversible_command (_("set sync point"));
3051 region->clear_changes ();
3052 region->set_sync_position (where);
3053 _session->add_command(new StatefulDiffCommand (region));
3057 commit_reversible_command ();
3061 /** Remove the sync positions of the selection */
3063 Editor::remove_region_sync ()
3065 RegionSelection rs = get_regions_from_selection_and_entered ();
3071 begin_reversible_command (_("remove region sync"));
3073 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3075 (*i)->region()->clear_changes ();
3076 (*i)->region()->clear_sync_position ();
3077 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3080 commit_reversible_command ();
3084 Editor::naturalize_region ()
3086 RegionSelection rs = get_regions_from_selection_and_entered ();
3092 if (rs.size() > 1) {
3093 begin_reversible_command (_("move regions to original position"));
3095 begin_reversible_command (_("move region to original position"));
3098 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3099 (*i)->region()->clear_changes ();
3100 (*i)->region()->move_to_natural_position ();
3101 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3104 commit_reversible_command ();
3108 Editor::align_regions (RegionPoint what)
3110 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3116 begin_reversible_command (_("align selection"));
3118 framepos_t const position = get_preferred_edit_position ();
3120 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3121 align_region_internal ((*i)->region(), what, position);
3124 commit_reversible_command ();
3127 struct RegionSortByTime {
3128 bool operator() (const RegionView* a, const RegionView* b) {
3129 return a->region()->position() < b->region()->position();
3134 Editor::align_regions_relative (RegionPoint point)
3136 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3142 framepos_t const position = get_preferred_edit_position ();
3144 framepos_t distance = 0;
3148 list<RegionView*> sorted;
3149 rs.by_position (sorted);
3151 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3156 if (position > r->position()) {
3157 distance = position - r->position();
3159 distance = r->position() - position;
3165 if (position > r->last_frame()) {
3166 distance = position - r->last_frame();
3167 pos = r->position() + distance;
3169 distance = r->last_frame() - position;
3170 pos = r->position() - distance;
3176 pos = r->adjust_to_sync (position);
3177 if (pos > r->position()) {
3178 distance = pos - r->position();
3180 distance = r->position() - pos;
3186 if (pos == r->position()) {
3190 begin_reversible_command (_("align selection (relative)"));
3192 /* move first one specially */
3194 r->clear_changes ();
3195 r->set_position (pos);
3196 _session->add_command(new StatefulDiffCommand (r));
3198 /* move rest by the same amount */
3202 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3204 boost::shared_ptr<Region> region ((*i)->region());
3206 region->clear_changes ();
3209 region->set_position (region->position() + distance);
3211 region->set_position (region->position() - distance);
3214 _session->add_command(new StatefulDiffCommand (region));
3218 commit_reversible_command ();
3222 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3224 begin_reversible_command (_("align region"));
3225 align_region_internal (region, point, position);
3226 commit_reversible_command ();
3230 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3232 region->clear_changes ();
3236 region->set_position (region->adjust_to_sync (position));
3240 if (position > region->length()) {
3241 region->set_position (position - region->length());
3246 region->set_position (position);
3250 _session->add_command(new StatefulDiffCommand (region));
3254 Editor::trim_region_front ()
3260 Editor::trim_region_back ()
3262 trim_region (false);
3266 Editor::trim_region (bool front)
3268 framepos_t where = get_preferred_edit_position();
3269 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3275 begin_reversible_command (front ? _("trim front") : _("trim back"));
3277 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3278 if (!(*i)->region()->locked()) {
3280 (*i)->region()->clear_changes ();
3283 (*i)->region()->trim_front (where);
3284 maybe_locate_with_edit_preroll ( where );
3286 (*i)->region()->trim_end (where);
3287 maybe_locate_with_edit_preroll ( where );
3290 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3294 commit_reversible_command ();
3297 /** Trim the end of the selected regions to the position of the edit cursor */
3299 Editor::trim_region_to_loop ()
3301 Location* loc = _session->locations()->auto_loop_location();
3305 trim_region_to_location (*loc, _("trim to loop"));
3309 Editor::trim_region_to_punch ()
3311 Location* loc = _session->locations()->auto_punch_location();
3315 trim_region_to_location (*loc, _("trim to punch"));
3319 Editor::trim_region_to_location (const Location& loc, const char* str)
3321 RegionSelection rs = get_regions_from_selection_and_entered ();
3323 begin_reversible_command (str);
3325 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3326 RegionView* rv = (*x);
3328 /* require region to span proposed trim */
3329 switch (rv->region()->coverage (loc.start(), loc.end())) {
3330 case Evoral::OverlapInternal:
3336 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3345 if (tav->track() != 0) {
3346 speed = tav->track()->speed();
3349 start = session_frame_to_track_frame (loc.start(), speed);
3350 end = session_frame_to_track_frame (loc.end(), speed);
3352 rv->region()->clear_changes ();
3353 rv->region()->trim_to (start, (end - start));
3354 _session->add_command(new StatefulDiffCommand (rv->region()));
3357 commit_reversible_command ();
3361 Editor::trim_region_to_previous_region_end ()
3363 return trim_to_region(false);
3367 Editor::trim_region_to_next_region_start ()
3369 return trim_to_region(true);
3373 Editor::trim_to_region(bool forward)
3375 RegionSelection rs = get_regions_from_selection_and_entered ();
3377 begin_reversible_command (_("trim to region"));
3379 boost::shared_ptr<Region> next_region;
3381 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3383 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3389 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3397 if (atav->track() != 0) {
3398 speed = atav->track()->speed();
3402 boost::shared_ptr<Region> region = arv->region();
3403 boost::shared_ptr<Playlist> playlist (region->playlist());
3405 region->clear_changes ();
3409 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3415 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3416 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3420 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3426 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3428 arv->region_changed (ARDOUR::bounds_change);
3431 _session->add_command(new StatefulDiffCommand (region));
3434 commit_reversible_command ();
3438 Editor::unfreeze_route ()
3440 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3444 clicked_routeview->track()->unfreeze ();
3448 Editor::_freeze_thread (void* arg)
3450 return static_cast<Editor*>(arg)->freeze_thread ();
3454 Editor::freeze_thread ()
3456 /* create event pool because we may need to talk to the session */
3457 SessionEvent::create_per_thread_pool ("freeze events", 64);
3458 /* create per-thread buffers for process() tree to use */
3459 current_interthread_info->process_thread.get_buffers ();
3460 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3461 current_interthread_info->done = true;
3462 current_interthread_info->process_thread.drop_buffers();
3467 Editor::freeze_route ()
3473 /* stop transport before we start. this is important */
3475 _session->request_transport_speed (0.0);
3477 /* wait for just a little while, because the above call is asynchronous */
3481 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3485 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3487 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3488 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3490 d.set_title (_("Cannot freeze"));
3495 if (clicked_routeview->track()->has_external_redirects()) {
3496 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"
3497 "Freezing will only process the signal as far as the first send/insert/return."),
3498 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3500 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3501 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3502 d.set_title (_("Freeze Limits"));
3504 int response = d.run ();
3507 case Gtk::RESPONSE_CANCEL:
3514 InterThreadInfo itt;
3515 current_interthread_info = &itt;
3517 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3519 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3521 set_canvas_cursor (_cursors->wait);
3523 while (!itt.done && !itt.cancel) {
3524 gtk_main_iteration ();
3527 current_interthread_info = 0;
3528 set_canvas_cursor (current_canvas_cursor);
3532 Editor::bounce_range_selection (bool replace, bool enable_processing)
3534 if (selection->time.empty()) {
3538 TrackSelection views = selection->tracks;
3540 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3542 if (enable_processing) {
3544 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3546 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3548 _("You can't perform this operation because the processing of the signal "
3549 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3550 "You can do this without processing, which is a different operation.")
3552 d.set_title (_("Cannot bounce"));
3559 framepos_t start = selection->time[clicked_selection].start;
3560 framepos_t end = selection->time[clicked_selection].end;
3561 framepos_t cnt = end - start + 1;
3563 begin_reversible_command (_("bounce range"));
3565 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3567 RouteTimeAxisView* rtv;
3569 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3573 boost::shared_ptr<Playlist> playlist;
3575 if ((playlist = rtv->playlist()) == 0) {
3579 InterThreadInfo itt;
3581 playlist->clear_changes ();
3582 playlist->clear_owned_changes ();
3584 boost::shared_ptr<Region> r;
3586 if (enable_processing) {
3587 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3589 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3597 list<AudioRange> ranges;
3598 ranges.push_back (AudioRange (start, start+cnt, 0));
3599 playlist->cut (ranges); // discard result
3600 playlist->add_region (r, start);
3603 vector<Command*> cmds;
3604 playlist->rdiff (cmds);
3605 _session->add_commands (cmds);
3607 _session->add_command (new StatefulDiffCommand (playlist));
3610 commit_reversible_command ();
3613 /** Delete selected regions, automation points or a time range */
3620 /** Cut selected regions, automation points or a time range */
3627 /** Copy selected regions, automation points or a time range */
3635 /** @return true if a Cut, Copy or Clear is possible */
3637 Editor::can_cut_copy () const
3639 switch (effective_mouse_mode()) {
3642 if (!selection->regions.empty() || !selection->points.empty()) {
3648 if (!selection->time.empty()) {
3661 /** Cut, copy or clear selected regions, automation points or a time range.
3662 * @param op Operation (Cut, Copy or Clear)
3665 Editor::cut_copy (CutCopyOp op)
3667 /* only cancel selection if cut/copy is successful.*/
3673 opname = _("delete");
3682 opname = _("clear");
3686 /* if we're deleting something, and the mouse is still pressed,
3687 the thing we started a drag for will be gone when we release
3688 the mouse button(s). avoid this. see part 2 at the end of
3692 if (op == Delete || op == Cut || op == Clear) {
3693 if (_drags->active ()) {
3698 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3699 cut_buffer->clear ();
3701 if (entered_marker) {
3703 /* cut/delete op while pointing at a marker */
3706 Location* loc = find_location_from_marker (entered_marker, ignored);
3708 if (_session && loc) {
3709 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3716 if (internal_editing()) {
3718 switch (effective_mouse_mode()) {
3731 /* we only want to cut regions if some are selected */
3733 if (!selection->regions.empty()) {
3734 rs = selection->regions;
3737 switch (effective_mouse_mode()) {
3740 //find regions's gain line
3741 AudioRegionView *rview = dynamic_cast<AudioRegionView*>(clicked_regionview);
3742 AutomationTimeAxisView *tview = dynamic_cast<AutomationTimeAxisView*>(clicked_trackview);
3744 AudioRegionGainLine *line = rview->get_gain_line();
3747 //cut region gain points in the selection
3748 AutomationList& alist (line->the_list());
3749 XMLNode &before = alist.get_state();
3750 AutomationList* what_we_got = 0;
3751 if ((what_we_got = alist.cut (selection->time.front().start - rview->audio_region()->position(), selection->time.front().end - rview->audio_region()->position())) != 0) {
3752 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3757 rview->set_envelope_visible(true);
3758 rview->audio_region()->set_envelope_active(true);
3761 AutomationLine *line = *(tview->lines.begin());
3764 //cut auto points in the selection
3765 AutomationList& alist (line->the_list());
3766 XMLNode &before = alist.get_state();
3767 AutomationList* what_we_got = 0;
3768 if ((what_we_got = alist.cut (selection->time.front().start, selection->time.front().end)) != 0) {
3769 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3779 if (!rs.empty() || !selection->points.empty()) {
3780 begin_reversible_command (opname + _(" objects"));
3783 cut_copy_regions (op, rs);
3785 if (op == Cut || op == Delete) {
3786 selection->clear_regions ();
3790 if (!selection->points.empty()) {
3791 cut_copy_points (op);
3793 if (op == Cut || op == Delete) {
3794 selection->clear_points ();
3798 commit_reversible_command ();
3802 if (selection->time.empty()) {
3803 framepos_t start, end;
3804 if (!get_edit_op_range (start, end)) {
3807 selection->set (start, end);
3810 begin_reversible_command (opname + _(" range"));
3811 cut_copy_ranges (op);
3812 commit_reversible_command ();
3814 if (op == Cut || op == Delete) {
3815 selection->clear_time ();
3825 if (op == Delete || op == Cut || op == Clear) {
3830 struct AutomationRecord {
3831 AutomationRecord () : state (0) {}
3832 AutomationRecord (XMLNode* s) : state (s) {}
3834 XMLNode* state; ///< state before any operation
3835 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3838 /** Cut, copy or clear selected automation points.
3839 * @param op Operation (Cut, Copy or Clear)
3842 Editor::cut_copy_points (CutCopyOp op)
3844 if (selection->points.empty ()) {
3848 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3849 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3851 /* Keep a record of the AutomationLists that we end up using in this operation */
3852 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3855 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3856 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3857 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3858 if (lists.find (al) == lists.end ()) {
3859 /* We haven't seen this list yet, so make a record for it. This includes
3860 taking a copy of its current state, in case this is needed for undo later.
3862 lists[al] = AutomationRecord (&al->get_state ());
3866 if (op == Cut || op == Copy) {
3867 /* This operation will involve putting things in the cut buffer, so create an empty
3868 ControlList for each of our source lists to put the cut buffer data in.
3870 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3871 i->second.copy = i->first->create (i->first->parameter ());
3874 /* Add all selected points to the relevant copy ControlLists */
3875 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3876 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3877 AutomationList::const_iterator j = (*i)->model ();
3878 lists[al].copy->add ((*j)->when, (*j)->value);
3881 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3882 /* Correct this copy list so that it starts at time 0 */
3883 double const start = i->second.copy->front()->when;
3884 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3885 (*j)->when -= start;
3888 /* And add it to the cut buffer */
3889 cut_buffer->add (i->second.copy);
3893 if (op == Delete || op == Cut) {
3894 /* This operation needs to remove things from the main AutomationList, so do that now */
3896 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3897 i->first->freeze ();
3900 /* Remove each selected point from its AutomationList */
3901 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3902 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3903 al->erase ((*i)->model ());
3906 /* Thaw the lists and add undo records for them */
3907 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3908 boost::shared_ptr<AutomationList> al = i->first;
3910 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3915 /** Cut, copy or clear selected automation points.
3916 * @param op Operation (Cut, Copy or Clear)
3919 Editor::cut_copy_midi (CutCopyOp op)
3921 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3922 MidiRegionView* mrv = *i;
3923 mrv->cut_copy_clear (op);
3929 struct lt_playlist {
3930 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3931 return a.playlist < b.playlist;
3935 struct PlaylistMapping {
3937 boost::shared_ptr<Playlist> pl;
3939 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3942 /** Remove `clicked_regionview' */
3944 Editor::remove_clicked_region ()
3946 if (clicked_routeview == 0 || clicked_regionview == 0) {
3950 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3952 begin_reversible_command (_("remove region"));
3953 playlist->clear_changes ();
3954 playlist->clear_owned_changes ();
3955 playlist->remove_region (clicked_regionview->region());
3957 /* We might have removed regions, which alters other regions' layering_index,
3958 so we need to do a recursive diff here.
3960 vector<Command*> cmds;
3961 playlist->rdiff (cmds);
3962 _session->add_commands (cmds);
3964 _session->add_command(new StatefulDiffCommand (playlist));
3965 commit_reversible_command ();
3969 /** Remove the selected regions */
3971 Editor::remove_selected_regions ()
3973 RegionSelection rs = get_regions_from_selection_and_entered ();
3975 if (!_session || rs.empty()) {
3979 begin_reversible_command (_("remove region"));
3981 list<boost::shared_ptr<Region> > regions_to_remove;
3983 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3984 // we can't just remove the region(s) in this loop because
3985 // this removes them from the RegionSelection, and they thus
3986 // disappear from underneath the iterator, and the ++i above
3987 // SEGVs in a puzzling fashion.
3989 // so, first iterate over the regions to be removed from rs and
3990 // add them to the regions_to_remove list, and then
3991 // iterate over the list to actually remove them.
3993 regions_to_remove.push_back ((*i)->region());
3996 vector<boost::shared_ptr<Playlist> > playlists;
3998 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4000 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4003 // is this check necessary?
4007 /* get_regions_from_selection_and_entered() guarantees that
4008 the playlists involved are unique, so there is no need
4012 playlists.push_back (playlist);
4014 playlist->clear_changes ();
4015 playlist->clear_owned_changes ();
4016 playlist->freeze ();
4017 playlist->remove_region (*rl);
4020 vector<boost::shared_ptr<Playlist> >::iterator pl;
4022 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4025 /* We might have removed regions, which alters other regions' layering_index,
4026 so we need to do a recursive diff here.
4028 vector<Command*> cmds;
4029 (*pl)->rdiff (cmds);
4030 _session->add_commands (cmds);
4032 _session->add_command(new StatefulDiffCommand (*pl));
4035 commit_reversible_command ();
4038 /** Cut, copy or clear selected regions.
4039 * @param op Operation (Cut, Copy or Clear)
4042 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4044 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4045 a map when we want ordered access to both elements. i think.
4048 vector<PlaylistMapping> pmap;
4050 framepos_t first_position = max_framepos;
4052 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4053 FreezeList freezelist;
4055 /* get ordering correct before we cut/copy */
4057 rs.sort_by_position_and_track ();
4059 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4061 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4063 if (op == Cut || op == Clear || op == Delete) {
4064 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4067 FreezeList::iterator fl;
4069 // only take state if this is a new playlist.
4070 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4076 if (fl == freezelist.end()) {
4077 pl->clear_changes();
4078 pl->clear_owned_changes ();
4080 freezelist.insert (pl);
4085 TimeAxisView* tv = &(*x)->get_time_axis_view();
4086 vector<PlaylistMapping>::iterator z;
4088 for (z = pmap.begin(); z != pmap.end(); ++z) {
4089 if ((*z).tv == tv) {
4094 if (z == pmap.end()) {
4095 pmap.push_back (PlaylistMapping (tv));
4099 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4101 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4104 /* region not yet associated with a playlist (e.g. unfinished
4111 TimeAxisView& tv = (*x)->get_time_axis_view();
4112 boost::shared_ptr<Playlist> npl;
4113 RegionSelection::iterator tmp;
4120 vector<PlaylistMapping>::iterator z;
4122 for (z = pmap.begin(); z != pmap.end(); ++z) {
4123 if ((*z).tv == &tv) {
4128 assert (z != pmap.end());
4131 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4139 boost::shared_ptr<Region> r = (*x)->region();
4140 boost::shared_ptr<Region> _xx;
4146 pl->remove_region (r);
4150 _xx = RegionFactory::create (r);
4151 npl->add_region (_xx, r->position() - first_position);
4152 pl->remove_region (r);
4156 /* copy region before adding, so we're not putting same object into two different playlists */
4157 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4161 pl->remove_region (r);
4170 list<boost::shared_ptr<Playlist> > foo;
4172 /* the pmap is in the same order as the tracks in which selected regions occured */
4174 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4177 foo.push_back ((*i).pl);
4182 cut_buffer->set (foo);
4186 _last_cut_copy_source_track = 0;
4188 _last_cut_copy_source_track = pmap.front().tv;
4192 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4195 /* We might have removed regions, which alters other regions' layering_index,
4196 so we need to do a recursive diff here.
4198 vector<Command*> cmds;
4199 (*pl)->rdiff (cmds);
4200 _session->add_commands (cmds);
4202 _session->add_command (new StatefulDiffCommand (*pl));
4207 Editor::cut_copy_ranges (CutCopyOp op)
4209 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4211 /* Sort the track selection now, so that it if is used, the playlists
4212 selected by the calls below to cut_copy_clear are in the order that
4213 their tracks appear in the editor. This makes things like paste
4214 of ranges work properly.
4217 sort_track_selection (ts);
4220 if (!entered_track) {
4223 ts.push_back (entered_track);
4226 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4227 (*i)->cut_copy_clear (*selection, op);
4232 Editor::paste (float times, bool from_context)
4234 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4236 paste_internal (get_preferred_edit_position (false, from_context), times);
4240 Editor::mouse_paste ()
4245 if (!mouse_frame (where, ignored)) {
4250 paste_internal (where, 1);
4254 Editor::paste_internal (framepos_t position, float times)
4256 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4258 if (internal_editing()) {
4259 if (cut_buffer->midi_notes.empty()) {
4263 if (cut_buffer->empty()) {
4268 if (position == max_framepos) {
4269 position = get_preferred_edit_position();
4270 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4274 TrackViewList::iterator i;
4277 /* get everything in the correct order */
4279 if (_edit_point == Editing::EditAtMouse && entered_track) {
4280 /* With the mouse edit point, paste onto the track under the mouse */
4281 ts.push_back (entered_track);
4282 } else if (!selection->tracks.empty()) {
4283 /* Otherwise, if there are some selected tracks, paste to them */
4284 ts = selection->tracks.filter_to_unique_playlists ();
4285 sort_track_selection (ts);
4286 } else if (_last_cut_copy_source_track) {
4287 /* Otherwise paste to the track that the cut/copy came from;
4288 see discussion in mantis #3333.
4290 ts.push_back (_last_cut_copy_source_track);
4293 if (internal_editing ()) {
4295 /* undo/redo is handled by individual tracks/regions */
4297 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4300 RegionSelection::iterator r;
4301 MidiNoteSelection::iterator cb;
4303 get_regions_at (rs, position, ts);
4305 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4306 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4307 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4309 mrv->paste (position, times, **cb);
4317 /* we do redo (do you do voodoo?) */
4319 begin_reversible_command (Operations::paste);
4321 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4322 (*i)->paste (position, times, *cut_buffer, nth);
4325 commit_reversible_command ();
4330 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4332 boost::shared_ptr<Playlist> playlist;
4333 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4334 RegionSelection foo;
4336 framepos_t const start_frame = regions.start ();
4337 framepos_t const end_frame = regions.end_frame ();
4339 begin_reversible_command (Operations::duplicate_region);
4341 selection->clear_regions ();
4343 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4345 boost::shared_ptr<Region> r ((*i)->region());
4347 TimeAxisView& tv = (*i)->get_time_axis_view();
4348 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4349 latest_regionviews.clear ();
4350 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4352 playlist = (*i)->region()->playlist();
4353 playlist->clear_changes ();
4354 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4355 _session->add_command(new StatefulDiffCommand (playlist));
4359 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4362 commit_reversible_command ();
4365 selection->set (foo);
4370 Editor::duplicate_selection (float times)
4372 if (selection->time.empty() || selection->tracks.empty()) {
4376 boost::shared_ptr<Playlist> playlist;
4377 vector<boost::shared_ptr<Region> > new_regions;
4378 vector<boost::shared_ptr<Region> >::iterator ri;
4380 create_region_from_selection (new_regions);
4382 if (new_regions.empty()) {
4386 begin_reversible_command (_("duplicate selection"));
4388 ri = new_regions.begin();
4390 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4392 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4393 if ((playlist = (*i)->playlist()) == 0) {
4396 playlist->clear_changes ();
4397 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4398 _session->add_command (new StatefulDiffCommand (playlist));
4401 if (ri == new_regions.end()) {
4406 commit_reversible_command ();
4409 /** Reset all selected points to the relevant default value */
4411 Editor::reset_point_selection ()
4413 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4414 ARDOUR::AutomationList::iterator j = (*i)->model ();
4415 (*j)->value = (*i)->line().the_list()->default_value ();
4420 Editor::center_playhead ()
4422 float const page = _visible_canvas_width * samples_per_pixel;
4423 center_screen_internal (playhead_cursor->current_frame (), page);
4427 Editor::center_edit_point ()
4429 float const page = _visible_canvas_width * samples_per_pixel;
4430 center_screen_internal (get_preferred_edit_position(), page);
4433 /** Caller must begin and commit a reversible command */
4435 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4437 playlist->clear_changes ();
4439 _session->add_command (new StatefulDiffCommand (playlist));
4443 Editor::nudge_track (bool use_edit, bool forwards)
4445 boost::shared_ptr<Playlist> playlist;
4446 framepos_t distance;
4447 framepos_t next_distance;
4451 start = get_preferred_edit_position();
4456 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4460 if (selection->tracks.empty()) {
4464 begin_reversible_command (_("nudge track"));
4466 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4468 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4470 if ((playlist = (*i)->playlist()) == 0) {
4474 playlist->clear_changes ();
4475 playlist->clear_owned_changes ();
4477 playlist->nudge_after (start, distance, forwards);
4479 vector<Command*> cmds;
4481 playlist->rdiff (cmds);
4482 _session->add_commands (cmds);
4484 _session->add_command (new StatefulDiffCommand (playlist));
4487 commit_reversible_command ();
4491 Editor::remove_last_capture ()
4493 vector<string> choices;
4500 if (Config->get_verify_remove_last_capture()) {
4501 prompt = _("Do you really want to destroy the last capture?"
4502 "\n(This is destructive and cannot be undone)");
4504 choices.push_back (_("No, do nothing."));
4505 choices.push_back (_("Yes, destroy it."));
4507 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4509 if (prompter.run () == 1) {
4510 _session->remove_last_capture ();
4511 _regions->redisplay ();
4515 _session->remove_last_capture();
4516 _regions->redisplay ();
4521 Editor::normalize_region ()
4527 RegionSelection rs = get_regions_from_selection_and_entered ();
4533 NormalizeDialog dialog (rs.size() > 1);
4535 if (dialog.run () == RESPONSE_CANCEL) {
4539 set_canvas_cursor (_cursors->wait);
4542 /* XXX: should really only count audio regions here */
4543 int const regions = rs.size ();
4545 /* Make a list of the selected audio regions' maximum amplitudes, and also
4546 obtain the maximum amplitude of them all.
4548 list<double> max_amps;
4550 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4551 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4553 dialog.descend (1.0 / regions);
4554 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4557 /* the user cancelled the operation */
4558 set_canvas_cursor (current_canvas_cursor);
4562 max_amps.push_back (a);
4563 max_amp = max (max_amp, a);
4568 begin_reversible_command (_("normalize"));
4570 list<double>::const_iterator a = max_amps.begin ();
4572 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4573 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4578 arv->region()->clear_changes ();
4580 double const amp = dialog.normalize_individually() ? *a : max_amp;
4582 arv->audio_region()->normalize (amp, dialog.target ());
4583 _session->add_command (new StatefulDiffCommand (arv->region()));
4588 commit_reversible_command ();
4589 set_canvas_cursor (current_canvas_cursor);
4594 Editor::reset_region_scale_amplitude ()
4600 RegionSelection rs = get_regions_from_selection_and_entered ();
4606 begin_reversible_command ("reset gain");
4608 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4609 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4612 arv->region()->clear_changes ();
4613 arv->audio_region()->set_scale_amplitude (1.0f);
4614 _session->add_command (new StatefulDiffCommand (arv->region()));
4617 commit_reversible_command ();
4621 Editor::adjust_region_gain (bool up)
4623 RegionSelection rs = get_regions_from_selection_and_entered ();
4625 if (!_session || rs.empty()) {
4629 begin_reversible_command ("adjust region gain");
4631 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4632 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4637 arv->region()->clear_changes ();
4639 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4647 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4648 _session->add_command (new StatefulDiffCommand (arv->region()));
4651 commit_reversible_command ();
4656 Editor::reverse_region ()
4662 Reverse rev (*_session);
4663 apply_filter (rev, _("reverse regions"));
4667 Editor::strip_region_silence ()
4673 RegionSelection rs = get_regions_from_selection_and_entered ();
4679 std::list<RegionView*> audio_only;
4681 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4682 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4684 audio_only.push_back (arv);
4688 StripSilenceDialog d (_session, audio_only);
4689 int const r = d.run ();
4693 if (r == Gtk::RESPONSE_OK) {
4694 ARDOUR::AudioIntervalMap silences;
4695 d.silences (silences);
4696 StripSilence s (*_session, silences, d.fade_length());
4697 apply_filter (s, _("strip silence"), &d);
4702 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4704 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4705 mrv.selection_as_notelist (selected, true);
4707 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4708 v.push_back (selected);
4710 framepos_t pos_frames = mrv.midi_region()->position();
4711 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4713 return op (mrv.midi_region()->model(), pos_beats, v);
4717 Editor::apply_midi_note_edit_op (MidiOperator& op)
4721 RegionSelection rs = get_regions_from_selection_and_entered ();
4727 begin_reversible_command (op.name ());
4729 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4730 RegionSelection::iterator tmp = r;
4733 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4736 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4739 _session->add_command (cmd);
4746 commit_reversible_command ();
4750 Editor::fork_region ()
4752 RegionSelection rs = get_regions_from_selection_and_entered ();
4758 begin_reversible_command (_("Fork Region(s)"));
4760 set_canvas_cursor (_cursors->wait);
4763 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4764 RegionSelection::iterator tmp = r;
4767 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4770 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4771 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4773 playlist->clear_changes ();
4774 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4775 _session->add_command(new StatefulDiffCommand (playlist));
4781 commit_reversible_command ();
4783 set_canvas_cursor (current_canvas_cursor);
4787 Editor::quantize_region ()
4789 int selected_midi_region_cnt = 0;
4795 RegionSelection rs = get_regions_from_selection_and_entered ();
4801 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4802 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4804 selected_midi_region_cnt++;
4808 if (selected_midi_region_cnt == 0) {
4812 QuantizeDialog* qd = new QuantizeDialog (*this);
4815 const int r = qd->run ();
4818 if (r == Gtk::RESPONSE_OK) {
4819 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4820 qd->start_grid_size(), qd->end_grid_size(),
4821 qd->strength(), qd->swing(), qd->threshold());
4823 apply_midi_note_edit_op (quant);
4828 Editor::insert_patch_change (bool from_context)
4830 RegionSelection rs = get_regions_from_selection_and_entered ();
4836 const framepos_t p = get_preferred_edit_position (false, from_context);
4838 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4839 there may be more than one, but the PatchChangeDialog can only offer
4840 one set of patch menus.
4842 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4844 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4845 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4847 if (d.run() == RESPONSE_CANCEL) {
4851 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4852 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4854 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4855 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4862 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4864 RegionSelection rs = get_regions_from_selection_and_entered ();
4870 begin_reversible_command (command);
4872 set_canvas_cursor (_cursors->wait);
4876 int const N = rs.size ();
4878 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4879 RegionSelection::iterator tmp = r;
4882 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4884 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4887 progress->descend (1.0 / N);
4890 if (arv->audio_region()->apply (filter, progress) == 0) {
4892 playlist->clear_changes ();
4893 playlist->clear_owned_changes ();
4895 if (filter.results.empty ()) {
4897 /* no regions returned; remove the old one */
4898 playlist->remove_region (arv->region ());
4902 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4904 /* first region replaces the old one */
4905 playlist->replace_region (arv->region(), *res, (*res)->position());
4909 while (res != filter.results.end()) {
4910 playlist->add_region (*res, (*res)->position());
4916 /* We might have removed regions, which alters other regions' layering_index,
4917 so we need to do a recursive diff here.
4919 vector<Command*> cmds;
4920 playlist->rdiff (cmds);
4921 _session->add_commands (cmds);
4923 _session->add_command(new StatefulDiffCommand (playlist));
4929 progress->ascend ();
4937 commit_reversible_command ();
4940 set_canvas_cursor (current_canvas_cursor);
4944 Editor::external_edit_region ()
4950 Editor::reset_region_gain_envelopes ()
4952 RegionSelection rs = get_regions_from_selection_and_entered ();
4954 if (!_session || rs.empty()) {
4958 _session->begin_reversible_command (_("reset region gain"));
4960 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4961 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4963 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4964 XMLNode& before (alist->get_state());
4966 arv->audio_region()->set_default_envelope ();
4967 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4971 _session->commit_reversible_command ();
4975 Editor::set_region_gain_visibility (RegionView* rv)
4977 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4979 arv->update_envelope_visibility();
4984 Editor::set_gain_envelope_visibility ()
4990 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4991 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4993 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
4999 Editor::toggle_gain_envelope_active ()
5001 if (_ignore_region_action) {
5005 RegionSelection rs = get_regions_from_selection_and_entered ();
5007 if (!_session || rs.empty()) {
5011 _session->begin_reversible_command (_("region gain envelope active"));
5013 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5014 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5016 arv->region()->clear_changes ();
5017 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5018 _session->add_command (new StatefulDiffCommand (arv->region()));
5022 _session->commit_reversible_command ();
5026 Editor::toggle_region_lock ()
5028 if (_ignore_region_action) {
5032 RegionSelection rs = get_regions_from_selection_and_entered ();
5034 if (!_session || rs.empty()) {
5038 _session->begin_reversible_command (_("toggle region lock"));
5040 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5041 (*i)->region()->clear_changes ();
5042 (*i)->region()->set_locked (!(*i)->region()->locked());
5043 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5046 _session->commit_reversible_command ();
5050 Editor::toggle_region_video_lock ()
5052 if (_ignore_region_action) {
5056 RegionSelection rs = get_regions_from_selection_and_entered ();
5058 if (!_session || rs.empty()) {
5062 _session->begin_reversible_command (_("Toggle Video Lock"));
5064 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5065 (*i)->region()->clear_changes ();
5066 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5067 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5070 _session->commit_reversible_command ();
5074 Editor::toggle_region_lock_style ()
5076 if (_ignore_region_action) {
5080 RegionSelection rs = get_regions_from_selection_and_entered ();
5082 if (!_session || rs.empty()) {
5086 _session->begin_reversible_command (_("region lock style"));
5088 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5089 (*i)->region()->clear_changes ();
5090 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5091 (*i)->region()->set_position_lock_style (ns);
5092 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5095 _session->commit_reversible_command ();
5099 Editor::toggle_opaque_region ()
5101 if (_ignore_region_action) {
5105 RegionSelection rs = get_regions_from_selection_and_entered ();
5107 if (!_session || rs.empty()) {
5111 _session->begin_reversible_command (_("change region opacity"));
5113 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5114 (*i)->region()->clear_changes ();
5115 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5116 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5119 _session->commit_reversible_command ();
5123 Editor::toggle_record_enable ()
5125 bool new_state = false;
5127 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5128 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5131 if (!rtav->is_track())
5135 new_state = !rtav->track()->record_enabled();
5139 rtav->track()->set_record_enabled (new_state, this);
5144 Editor::toggle_solo ()
5146 bool new_state = false;
5148 boost::shared_ptr<RouteList> rl (new RouteList);
5150 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5151 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5158 new_state = !rtav->route()->soloed ();
5162 rl->push_back (rtav->route());
5165 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5169 Editor::toggle_mute ()
5171 bool new_state = false;
5173 boost::shared_ptr<RouteList> rl (new RouteList);
5175 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5176 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5183 new_state = !rtav->route()->muted();
5187 rl->push_back (rtav->route());
5190 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5194 Editor::toggle_solo_isolate ()
5199 Editor::set_fade_length (bool in)
5201 RegionSelection rs = get_regions_from_selection_and_entered ();
5207 /* we need a region to measure the offset from the start */
5209 RegionView* rv = rs.front ();
5211 framepos_t pos = get_preferred_edit_position();
5215 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5216 /* edit point is outside the relevant region */
5221 if (pos <= rv->region()->position()) {
5225 len = pos - rv->region()->position();
5226 cmd = _("set fade in length");
5228 if (pos >= rv->region()->last_frame()) {
5232 len = rv->region()->last_frame() - pos;
5233 cmd = _("set fade out length");
5236 begin_reversible_command (cmd);
5238 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5239 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5245 boost::shared_ptr<AutomationList> alist;
5247 alist = tmp->audio_region()->fade_in();
5249 alist = tmp->audio_region()->fade_out();
5252 XMLNode &before = alist->get_state();
5255 tmp->audio_region()->set_fade_in_length (len);
5256 tmp->audio_region()->set_fade_in_active (true);
5258 tmp->audio_region()->set_fade_out_length (len);
5259 tmp->audio_region()->set_fade_out_active (true);
5262 XMLNode &after = alist->get_state();
5263 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5266 commit_reversible_command ();
5270 Editor::set_fade_in_shape (FadeShape shape)
5272 RegionSelection rs = get_regions_from_selection_and_entered ();
5278 begin_reversible_command (_("set fade in shape"));
5280 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5281 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5287 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5288 XMLNode &before = alist->get_state();
5290 tmp->audio_region()->set_fade_in_shape (shape);
5292 XMLNode &after = alist->get_state();
5293 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5296 commit_reversible_command ();
5301 Editor::set_fade_out_shape (FadeShape shape)
5303 RegionSelection rs = get_regions_from_selection_and_entered ();
5309 begin_reversible_command (_("set fade out shape"));
5311 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5312 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5318 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5319 XMLNode &before = alist->get_state();
5321 tmp->audio_region()->set_fade_out_shape (shape);
5323 XMLNode &after = alist->get_state();
5324 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5327 commit_reversible_command ();
5331 Editor::set_fade_in_active (bool yn)
5333 RegionSelection rs = get_regions_from_selection_and_entered ();
5339 begin_reversible_command (_("set fade in active"));
5341 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5342 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5349 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5351 ar->clear_changes ();
5352 ar->set_fade_in_active (yn);
5353 _session->add_command (new StatefulDiffCommand (ar));
5356 commit_reversible_command ();
5360 Editor::set_fade_out_active (bool yn)
5362 RegionSelection rs = get_regions_from_selection_and_entered ();
5368 begin_reversible_command (_("set fade out active"));
5370 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5371 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5377 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5379 ar->clear_changes ();
5380 ar->set_fade_out_active (yn);
5381 _session->add_command(new StatefulDiffCommand (ar));
5384 commit_reversible_command ();
5388 Editor::toggle_region_fades (int dir)
5390 if (_ignore_region_action) {
5394 boost::shared_ptr<AudioRegion> ar;
5397 RegionSelection rs = get_regions_from_selection_and_entered ();
5403 RegionSelection::iterator i;
5404 for (i = rs.begin(); i != rs.end(); ++i) {
5405 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5407 yn = ar->fade_out_active ();
5409 yn = ar->fade_in_active ();
5415 if (i == rs.end()) {
5419 /* XXX should this undo-able? */
5421 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5422 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5425 if (dir == 1 || dir == 0) {
5426 ar->set_fade_in_active (!yn);
5429 if (dir == -1 || dir == 0) {
5430 ar->set_fade_out_active (!yn);
5436 /** Update region fade visibility after its configuration has been changed */
5438 Editor::update_region_fade_visibility ()
5440 bool _fade_visibility = _session->config.get_show_region_fades ();
5442 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5443 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5445 if (_fade_visibility) {
5446 v->audio_view()->show_all_fades ();
5448 v->audio_view()->hide_all_fades ();
5455 Editor::set_edit_point ()
5460 if (!mouse_frame (where, ignored)) {
5466 if (selection->markers.empty()) {
5468 mouse_add_new_marker (where);
5473 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5476 loc->move_to (where);
5482 Editor::set_playhead_cursor ()
5484 if (entered_marker) {
5485 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5490 if (!mouse_frame (where, ignored)) {
5497 _session->request_locate (where, _session->transport_rolling());
5501 if ( Config->get_always_play_range() )
5502 cancel_time_selection();
5506 Editor::split_region ()
5508 if ( !selection->time.empty()) {
5509 separate_regions_between (selection->time);
5513 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5515 framepos_t where = get_preferred_edit_position ();
5521 split_regions_at (where, rs);
5524 struct EditorOrderRouteSorter {
5525 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5526 return a->order_key (EditorSort) < b->order_key (EditorSort);
5531 Editor::select_next_route()
5533 if (selection->tracks.empty()) {
5534 selection->set (track_views.front());
5538 TimeAxisView* current = selection->tracks.front();
5542 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5543 if (*i == current) {
5545 if (i != track_views.end()) {
5548 current = (*(track_views.begin()));
5549 //selection->set (*(track_views.begin()));
5554 rui = dynamic_cast<RouteUI *>(current);
5555 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5557 selection->set(current);
5559 ensure_track_visible(current);
5563 Editor::select_prev_route()
5565 if (selection->tracks.empty()) {
5566 selection->set (track_views.front());
5570 TimeAxisView* current = selection->tracks.front();
5574 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5575 if (*i == current) {
5577 if (i != track_views.rend()) {
5580 current = *(track_views.rbegin());
5585 rui = dynamic_cast<RouteUI *>(current);
5586 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5588 selection->set (current);
5590 ensure_track_visible(current);
5594 Editor::ensure_track_visible(TimeAxisView *track)
5596 if (track->hidden())
5599 double const current_view_min_y = vertical_adjustment.get_value();
5600 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5602 double const track_min_y = track->y_position ();
5603 double const track_max_y = track->y_position () + track->effective_height ();
5605 if (track_min_y >= current_view_min_y &&
5606 track_max_y <= current_view_max_y) {
5612 if (track_min_y < current_view_min_y) {
5613 // Track is above the current view
5614 new_value = track_min_y;
5616 // Track is below the current view
5617 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5620 vertical_adjustment.set_value(new_value);
5624 Editor::set_loop_from_selection (bool play)
5626 if (_session == 0 || selection->time.empty()) {
5630 framepos_t start = selection->time[clicked_selection].start;
5631 framepos_t end = selection->time[clicked_selection].end;
5633 set_loop_range (start, end, _("set loop range from selection"));
5636 _session->request_play_loop (true);
5637 _session->request_locate (start, true);
5642 Editor::set_loop_from_edit_range (bool play)
5644 if (_session == 0) {
5651 if (!get_edit_op_range (start, end)) {
5655 set_loop_range (start, end, _("set loop range from edit range"));
5658 _session->request_play_loop (true);
5659 _session->request_locate (start, true);
5664 Editor::set_loop_from_region (bool play)
5666 framepos_t start = max_framepos;
5669 RegionSelection rs = get_regions_from_selection_and_entered ();
5675 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5676 if ((*i)->region()->position() < start) {
5677 start = (*i)->region()->position();
5679 if ((*i)->region()->last_frame() + 1 > end) {
5680 end = (*i)->region()->last_frame() + 1;
5684 set_loop_range (start, end, _("set loop range from region"));
5687 _session->request_play_loop (true);
5688 _session->request_locate (start, true);
5693 Editor::set_punch_from_selection ()
5695 if (_session == 0 || selection->time.empty()) {
5699 framepos_t start = selection->time[clicked_selection].start;
5700 framepos_t end = selection->time[clicked_selection].end;
5702 set_punch_range (start, end, _("set punch range from selection"));
5706 Editor::set_punch_from_edit_range ()
5708 if (_session == 0) {
5715 if (!get_edit_op_range (start, end)) {
5719 set_punch_range (start, end, _("set punch range from edit range"));
5723 Editor::set_punch_from_region ()
5725 framepos_t start = max_framepos;
5728 RegionSelection rs = get_regions_from_selection_and_entered ();
5734 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5735 if ((*i)->region()->position() < start) {
5736 start = (*i)->region()->position();
5738 if ((*i)->region()->last_frame() + 1 > end) {
5739 end = (*i)->region()->last_frame() + 1;
5743 set_punch_range (start, end, _("set punch range from region"));
5747 Editor::pitch_shift_region ()
5749 RegionSelection rs = get_regions_from_selection_and_entered ();
5751 RegionSelection audio_rs;
5752 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5753 if (dynamic_cast<AudioRegionView*> (*i)) {
5754 audio_rs.push_back (*i);
5758 if (audio_rs.empty()) {
5762 pitch_shift (audio_rs, 1.2);
5766 Editor::transpose_region ()
5768 RegionSelection rs = get_regions_from_selection_and_entered ();
5770 list<MidiRegionView*> midi_region_views;
5771 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5772 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5774 midi_region_views.push_back (mrv);
5779 int const r = d.run ();
5780 if (r != RESPONSE_ACCEPT) {
5784 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5785 (*i)->midi_region()->transpose (d.semitones ());
5790 Editor::set_tempo_from_region ()
5792 RegionSelection rs = get_regions_from_selection_and_entered ();
5794 if (!_session || rs.empty()) {
5798 RegionView* rv = rs.front();
5800 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5804 Editor::use_range_as_bar ()
5806 framepos_t start, end;
5807 if (get_edit_op_range (start, end)) {
5808 define_one_bar (start, end);
5813 Editor::define_one_bar (framepos_t start, framepos_t end)
5815 framepos_t length = end - start;
5817 const Meter& m (_session->tempo_map().meter_at (start));
5819 /* length = 1 bar */
5821 /* now we want frames per beat.
5822 we have frames per bar, and beats per bar, so ...
5825 /* XXXX METER MATH */
5827 double frames_per_beat = length / m.divisions_per_bar();
5829 /* beats per minute = */
5831 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5833 /* now decide whether to:
5835 (a) set global tempo
5836 (b) add a new tempo marker
5840 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5842 bool do_global = false;
5844 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5846 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5847 at the start, or create a new marker
5850 vector<string> options;
5851 options.push_back (_("Cancel"));
5852 options.push_back (_("Add new marker"));
5853 options.push_back (_("Set global tempo"));
5856 _("Define one bar"),
5857 _("Do you want to set the global tempo or add a new tempo marker?"),
5861 c.set_default_response (2);
5877 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5878 if the marker is at the region starter, change it, otherwise add
5883 begin_reversible_command (_("set tempo from region"));
5884 XMLNode& before (_session->tempo_map().get_state());
5887 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5888 } else if (t.frame() == start) {
5889 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5891 Timecode::BBT_Time bbt;
5892 _session->tempo_map().bbt_time (start, bbt);
5893 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5896 XMLNode& after (_session->tempo_map().get_state());
5898 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5899 commit_reversible_command ();
5903 Editor::split_region_at_transients ()
5905 AnalysisFeatureList positions;
5907 RegionSelection rs = get_regions_from_selection_and_entered ();
5909 if (!_session || rs.empty()) {
5913 _session->begin_reversible_command (_("split regions"));
5915 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5917 RegionSelection::iterator tmp;
5922 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5924 if (ar && (ar->get_transients (positions) == 0)) {
5925 split_region_at_points ((*i)->region(), positions, true);
5932 _session->commit_reversible_command ();
5937 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5939 bool use_rhythmic_rodent = false;
5941 boost::shared_ptr<Playlist> pl = r->playlist();
5943 list<boost::shared_ptr<Region> > new_regions;
5949 if (positions.empty()) {
5954 if (positions.size() > 20 && can_ferret) {
5955 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);
5956 MessageDialog msg (msgstr,
5959 Gtk::BUTTONS_OK_CANCEL);
5962 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5963 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5965 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5968 msg.set_title (_("Excessive split?"));
5971 int response = msg.run();
5977 case RESPONSE_APPLY:
5978 use_rhythmic_rodent = true;
5985 if (use_rhythmic_rodent) {
5986 show_rhythm_ferret ();
5990 AnalysisFeatureList::const_iterator x;
5992 pl->clear_changes ();
5993 pl->clear_owned_changes ();
5995 x = positions.begin();
5997 if (x == positions.end()) {
6002 pl->remove_region (r);
6006 while (x != positions.end()) {
6008 /* deal with positons that are out of scope of present region bounds */
6009 if (*x <= 0 || *x > r->length()) {
6014 /* file start = original start + how far we from the initial position ?
6017 framepos_t file_start = r->start() + pos;
6019 /* length = next position - current position
6022 framepos_t len = (*x) - pos;
6024 /* XXX we do we really want to allow even single-sample regions?
6025 shouldn't we have some kind of lower limit on region size?
6034 if (RegionFactory::region_name (new_name, r->name())) {
6038 /* do NOT announce new regions 1 by one, just wait till they are all done */
6042 plist.add (ARDOUR::Properties::start, file_start);
6043 plist.add (ARDOUR::Properties::length, len);
6044 plist.add (ARDOUR::Properties::name, new_name);
6045 plist.add (ARDOUR::Properties::layer, 0);
6047 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6048 /* because we set annouce to false, manually add the new region to the
6051 RegionFactory::map_add (nr);
6053 pl->add_region (nr, r->position() + pos);
6056 new_regions.push_front(nr);
6065 RegionFactory::region_name (new_name, r->name());
6067 /* Add the final region */
6070 plist.add (ARDOUR::Properties::start, r->start() + pos);
6071 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6072 plist.add (ARDOUR::Properties::name, new_name);
6073 plist.add (ARDOUR::Properties::layer, 0);
6075 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6076 /* because we set annouce to false, manually add the new region to the
6079 RegionFactory::map_add (nr);
6080 pl->add_region (nr, r->position() + pos);
6083 new_regions.push_front(nr);
6088 /* We might have removed regions, which alters other regions' layering_index,
6089 so we need to do a recursive diff here.
6091 vector<Command*> cmds;
6093 _session->add_commands (cmds);
6095 _session->add_command (new StatefulDiffCommand (pl));
6099 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6100 set_selected_regionview_from_region_list ((*i), Selection::Add);
6106 Editor::place_transient()
6112 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6118 framepos_t where = get_preferred_edit_position();
6120 _session->begin_reversible_command (_("place transient"));
6122 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6123 framepos_t position = (*r)->region()->position();
6124 (*r)->region()->add_transient(where - position);
6127 _session->commit_reversible_command ();
6131 Editor::remove_transient(ArdourCanvas::Item* item)
6137 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6140 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6141 _arv->remove_transient (*(float*) _line->get_data ("position"));
6145 Editor::snap_regions_to_grid ()
6147 list <boost::shared_ptr<Playlist > > used_playlists;
6149 RegionSelection rs = get_regions_from_selection_and_entered ();
6151 if (!_session || rs.empty()) {
6155 _session->begin_reversible_command (_("snap regions to grid"));
6157 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6159 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6161 if (!pl->frozen()) {
6162 /* we haven't seen this playlist before */
6164 /* remember used playlists so we can thaw them later */
6165 used_playlists.push_back(pl);
6169 framepos_t start_frame = (*r)->region()->first_frame ();
6170 snap_to (start_frame);
6171 (*r)->region()->set_position (start_frame);
6174 while (used_playlists.size() > 0) {
6175 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6177 used_playlists.pop_front();
6180 _session->commit_reversible_command ();
6184 Editor::close_region_gaps ()
6186 list <boost::shared_ptr<Playlist > > used_playlists;
6188 RegionSelection rs = get_regions_from_selection_and_entered ();
6190 if (!_session || rs.empty()) {
6194 Dialog dialog (_("Close Region Gaps"));
6197 table.set_spacings (12);
6198 table.set_border_width (12);
6199 Label* l = manage (left_aligned_label (_("Crossfade length")));
6200 table.attach (*l, 0, 1, 0, 1);
6202 SpinButton spin_crossfade (1, 0);
6203 spin_crossfade.set_range (0, 15);
6204 spin_crossfade.set_increments (1, 1);
6205 spin_crossfade.set_value (5);
6206 table.attach (spin_crossfade, 1, 2, 0, 1);
6208 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6210 l = manage (left_aligned_label (_("Pull-back length")));
6211 table.attach (*l, 0, 1, 1, 2);
6213 SpinButton spin_pullback (1, 0);
6214 spin_pullback.set_range (0, 100);
6215 spin_pullback.set_increments (1, 1);
6216 spin_pullback.set_value(30);
6217 table.attach (spin_pullback, 1, 2, 1, 2);
6219 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6221 dialog.get_vbox()->pack_start (table);
6222 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6223 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6226 if (dialog.run () == RESPONSE_CANCEL) {
6230 framepos_t crossfade_len = spin_crossfade.get_value();
6231 framepos_t pull_back_frames = spin_pullback.get_value();
6233 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6234 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6236 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6238 _session->begin_reversible_command (_("close region gaps"));
6241 boost::shared_ptr<Region> last_region;
6243 rs.sort_by_position_and_track();
6245 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6247 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6249 if (!pl->frozen()) {
6250 /* we haven't seen this playlist before */
6252 /* remember used playlists so we can thaw them later */
6253 used_playlists.push_back(pl);
6257 framepos_t position = (*r)->region()->position();
6259 if (idx == 0 || position < last_region->position()){
6260 last_region = (*r)->region();
6265 (*r)->region()->trim_front( (position - pull_back_frames));
6266 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6268 last_region = (*r)->region();
6273 while (used_playlists.size() > 0) {
6274 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6276 used_playlists.pop_front();
6279 _session->commit_reversible_command ();
6283 Editor::tab_to_transient (bool forward)
6285 AnalysisFeatureList positions;
6287 RegionSelection rs = get_regions_from_selection_and_entered ();
6293 framepos_t pos = _session->audible_frame ();
6295 if (!selection->tracks.empty()) {
6297 /* don't waste time searching for transients in duplicate playlists.
6300 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6302 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6304 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6307 boost::shared_ptr<Track> tr = rtv->track();
6309 boost::shared_ptr<Playlist> pl = tr->playlist ();
6311 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6314 positions.push_back (result);
6327 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6328 (*r)->region()->get_transients (positions);
6332 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6335 AnalysisFeatureList::iterator x;
6337 for (x = positions.begin(); x != positions.end(); ++x) {
6343 if (x != positions.end ()) {
6344 _session->request_locate (*x);
6348 AnalysisFeatureList::reverse_iterator x;
6350 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6356 if (x != positions.rend ()) {
6357 _session->request_locate (*x);
6363 Editor::playhead_forward_to_grid ()
6369 framepos_t pos = playhead_cursor->current_frame ();
6370 if (pos < max_framepos - 1) {
6372 snap_to_internal (pos, 1, false);
6373 _session->request_locate (pos);
6379 Editor::playhead_backward_to_grid ()
6385 framepos_t pos = playhead_cursor->current_frame ();
6388 snap_to_internal (pos, -1, false);
6389 _session->request_locate (pos);
6394 Editor::set_track_height (Height h)
6396 TrackSelection& ts (selection->tracks);
6398 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6399 (*x)->set_height_enum (h);
6404 Editor::toggle_tracks_active ()
6406 TrackSelection& ts (selection->tracks);
6408 bool target = false;
6414 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6415 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6419 target = !rtv->_route->active();
6422 rtv->_route->set_active (target, this);
6428 Editor::remove_tracks ()
6430 TrackSelection& ts (selection->tracks);
6436 vector<string> choices;
6440 const char* trackstr;
6442 vector<boost::shared_ptr<Route> > routes;
6443 bool special_bus = false;
6445 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6446 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6448 if (rtv->is_track()) {
6454 routes.push_back (rtv->_route);
6456 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6461 if (special_bus && !Config->get_allow_special_bus_removal()) {
6462 MessageDialog msg (_("That would be bad news ...."),
6466 msg.set_secondary_text (string_compose (_(
6467 "Removing the master or monitor bus is such a bad idea\n\
6468 that %1 is not going to allow it.\n\
6470 If you really want to do this sort of thing\n\
6471 edit your ardour.rc file to set the\n\
6472 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6479 if (ntracks + nbusses == 0) {
6484 trackstr = _("tracks");
6486 trackstr = _("track");
6490 busstr = _("busses");
6497 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6498 "(You may also lose the playlists associated with the %2)\n\n"
6499 "This action cannot be undone, and the session file will be overwritten!"),
6500 ntracks, trackstr, nbusses, busstr);
6502 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6503 "(You may also lose the playlists associated with the %2)\n\n"
6504 "This action cannot be undone, and the session file will be overwritten!"),
6507 } else if (nbusses) {
6508 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6509 "This action cannot be undon, and the session file will be overwritten"),
6513 choices.push_back (_("No, do nothing."));
6514 if (ntracks + nbusses > 1) {
6515 choices.push_back (_("Yes, remove them."));
6517 choices.push_back (_("Yes, remove it."));
6522 title = string_compose (_("Remove %1"), trackstr);
6524 title = string_compose (_("Remove %1"), busstr);
6527 Choice prompter (title, prompt, choices);
6529 if (prompter.run () != 1) {
6533 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6534 _session->remove_route (*x);
6539 Editor::do_insert_time ()
6541 if (selection->tracks.empty()) {
6545 InsertTimeDialog d (*this);
6546 int response = d.run ();
6548 if (response != RESPONSE_OK) {
6552 if (d.distance() == 0) {
6556 InsertTimeOption opt = d.intersected_region_action ();
6559 get_preferred_edit_position(),
6565 d.move_glued_markers(),
6566 d.move_locked_markers(),
6572 Editor::insert_time (
6573 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6574 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6577 bool commit = false;
6579 if (Config->get_edit_mode() == Lock) {
6583 begin_reversible_command (_("insert time"));
6585 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6587 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6591 /* don't operate on any playlist more than once, which could
6592 * happen if "all playlists" is enabled, but there is more
6593 * than 1 track using playlists "from" a given track.
6596 set<boost::shared_ptr<Playlist> > pl;
6598 if (all_playlists) {
6599 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6601 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6602 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6607 if ((*x)->playlist ()) {
6608 pl.insert ((*x)->playlist ());
6612 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6614 (*i)->clear_changes ();
6615 (*i)->clear_owned_changes ();
6617 if (opt == SplitIntersected) {
6621 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6623 vector<Command*> cmds;
6625 _session->add_commands (cmds);
6627 _session->add_command (new StatefulDiffCommand (*i));
6632 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6634 rtav->route ()->shift (pos, frames);
6642 XMLNode& before (_session->locations()->get_state());
6643 Locations::LocationList copy (_session->locations()->list());
6645 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6647 Locations::LocationList::const_iterator tmp;
6649 bool const was_locked = (*i)->locked ();
6650 if (locked_markers_too) {
6654 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6656 if ((*i)->start() >= pos) {
6657 (*i)->set_start ((*i)->start() + frames);
6658 if (!(*i)->is_mark()) {
6659 (*i)->set_end ((*i)->end() + frames);
6672 XMLNode& after (_session->locations()->get_state());
6673 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6678 _session->tempo_map().insert_time (pos, frames);
6682 commit_reversible_command ();
6687 Editor::fit_selected_tracks ()
6689 if (!selection->tracks.empty()) {
6690 fit_tracks (selection->tracks);
6694 /* no selected tracks - use tracks with selected regions */
6696 if (!selection->regions.empty()) {
6697 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6698 tvl.push_back (&(*r)->get_time_axis_view ());
6704 } else if (internal_editing()) {
6705 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6708 if (entered_track) {
6709 tvl.push_back (entered_track);
6717 Editor::fit_tracks (TrackViewList & tracks)
6719 if (tracks.empty()) {
6723 uint32_t child_heights = 0;
6724 int visible_tracks = 0;
6726 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6728 if (!(*t)->marked_for_display()) {
6732 child_heights += (*t)->effective_height() - (*t)->current_height();
6736 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6737 double first_y_pos = DBL_MAX;
6739 if (h < TimeAxisView::preset_height (HeightSmall)) {
6740 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6741 /* too small to be displayed */
6745 undo_visual_stack.push_back (current_visual_state (true));
6746 no_save_visual = true;
6748 /* build a list of all tracks, including children */
6751 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6753 TimeAxisView::Children c = (*i)->get_child_list ();
6754 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6755 all.push_back (j->get());
6759 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6761 bool prev_was_selected = false;
6762 bool is_selected = tracks.contains (all.front());
6763 bool next_is_selected;
6765 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6767 TrackViewList::iterator next;
6772 if (next != all.end()) {
6773 next_is_selected = tracks.contains (*next);
6775 next_is_selected = false;
6778 if ((*t)->marked_for_display ()) {
6780 (*t)->set_height (h);
6781 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6783 if (prev_was_selected && next_is_selected) {
6784 hide_track_in_display (*t);
6789 prev_was_selected = is_selected;
6790 is_selected = next_is_selected;
6794 set the controls_layout height now, because waiting for its size
6795 request signal handler will cause the vertical adjustment setting to fail
6798 controls_layout.property_height () = _full_canvas_height;
6799 vertical_adjustment.set_value (first_y_pos);
6801 redo_visual_stack.push_back (current_visual_state (true));
6805 Editor::save_visual_state (uint32_t n)
6807 while (visual_states.size() <= n) {
6808 visual_states.push_back (0);
6811 if (visual_states[n] != 0) {
6812 delete visual_states[n];
6815 visual_states[n] = current_visual_state (true);
6820 Editor::goto_visual_state (uint32_t n)
6822 if (visual_states.size() <= n) {
6826 if (visual_states[n] == 0) {
6830 use_visual_state (*visual_states[n]);
6834 Editor::start_visual_state_op (uint32_t n)
6836 save_visual_state (n);
6838 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6840 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6841 pup->set_text (buf);
6846 Editor::cancel_visual_state_op (uint32_t n)
6848 goto_visual_state (n);
6852 Editor::toggle_region_mute ()
6854 if (_ignore_region_action) {
6858 RegionSelection rs = get_regions_from_selection_and_entered ();
6864 if (rs.size() > 1) {
6865 begin_reversible_command (_("mute regions"));
6867 begin_reversible_command (_("mute region"));
6870 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6872 (*i)->region()->playlist()->clear_changes ();
6873 (*i)->region()->set_muted (!(*i)->region()->muted ());
6874 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6878 commit_reversible_command ();
6882 Editor::combine_regions ()
6884 /* foreach track with selected regions, take all selected regions
6885 and join them into a new region containing the subregions (as a
6889 typedef set<RouteTimeAxisView*> RTVS;
6892 if (selection->regions.empty()) {
6896 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6897 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6900 tracks.insert (rtv);
6904 begin_reversible_command (_("combine regions"));
6906 vector<RegionView*> new_selection;
6908 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6911 if ((rv = (*i)->combine_regions ()) != 0) {
6912 new_selection.push_back (rv);
6916 selection->clear_regions ();
6917 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6918 selection->add (*i);
6921 commit_reversible_command ();
6925 Editor::uncombine_regions ()
6927 typedef set<RouteTimeAxisView*> RTVS;
6930 if (selection->regions.empty()) {
6934 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6935 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6938 tracks.insert (rtv);
6942 begin_reversible_command (_("uncombine regions"));
6944 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6945 (*i)->uncombine_regions ();
6948 commit_reversible_command ();
6952 Editor::toggle_midi_input_active (bool flip_others)
6955 boost::shared_ptr<RouteList> rl (new RouteList);
6957 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6958 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6964 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6967 rl->push_back (rtav->route());
6968 onoff = !mt->input_active();
6972 _session->set_exclusive_input_active (rl, onoff, flip_others);