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 (framecnt_t& fpp) const
1336 bool clamped = false;
1343 if (max_framepos / fpp < 800) {
1344 fpp = max_framepos / 800;
1352 Editor::temporal_zoom_step (bool coarser)
1354 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1356 framecnt_t nspp = samples_per_pixel;
1364 temporal_zoom (nspp);
1368 Editor::temporal_zoom (framecnt_t 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) {
1391 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1392 // segfaults for lack of memory. If somebody decides this is not high enough I
1393 // believe it can be raisen to higher values but some limit must be in place.
1395 nfpp = min (fpp, (framecnt_t) 8589934592);
1396 nfpp = max ((framecnt_t) 1, fpp);
1398 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1399 half_page_size = new_page_size / 2;
1401 switch (zoom_focus) {
1403 leftmost_after_zoom = current_leftmost;
1406 case ZoomFocusRight:
1407 current_rightmost = leftmost_frame + current_page;
1408 if (current_rightmost < new_page_size) {
1409 leftmost_after_zoom = 0;
1411 leftmost_after_zoom = current_rightmost - new_page_size;
1415 case ZoomFocusCenter:
1416 current_center = current_leftmost + (current_page/2);
1417 if (current_center < half_page_size) {
1418 leftmost_after_zoom = 0;
1420 leftmost_after_zoom = current_center - half_page_size;
1424 case ZoomFocusPlayhead:
1425 /* centre playhead */
1426 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1429 leftmost_after_zoom = 0;
1430 } else if (l > max_framepos) {
1431 leftmost_after_zoom = max_framepos - new_page_size;
1433 leftmost_after_zoom = (framepos_t) l;
1437 case ZoomFocusMouse:
1438 /* try to keep the mouse over the same point in the display */
1440 if (!mouse_frame (where, in_track_canvas)) {
1441 /* use playhead instead */
1442 where = playhead_cursor->current_frame ();
1444 if (where < half_page_size) {
1445 leftmost_after_zoom = 0;
1447 leftmost_after_zoom = where - half_page_size;
1452 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1455 leftmost_after_zoom = 0;
1456 } else if (l > max_framepos) {
1457 leftmost_after_zoom = max_framepos - new_page_size;
1459 leftmost_after_zoom = (framepos_t) l;
1466 /* try to keep the edit point in the same place */
1467 where = get_preferred_edit_position ();
1471 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1474 leftmost_after_zoom = 0;
1475 } else if (l > max_framepos) {
1476 leftmost_after_zoom = max_framepos - new_page_size;
1478 leftmost_after_zoom = (framepos_t) l;
1482 /* edit point not defined */
1489 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1491 reposition_and_zoom (leftmost_after_zoom, nfpp);
1495 Editor::temporal_zoom_region (bool both_axes)
1497 framepos_t start = max_framepos;
1499 set<TimeAxisView*> tracks;
1501 RegionSelection rs = get_regions_from_selection_and_entered ();
1507 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1509 if ((*i)->region()->position() < start) {
1510 start = (*i)->region()->position();
1513 if ((*i)->region()->last_frame() + 1 > end) {
1514 end = (*i)->region()->last_frame() + 1;
1517 tracks.insert (&((*i)->get_time_axis_view()));
1520 /* now comes an "interesting" hack ... make sure we leave a little space
1521 at each end of the editor so that the zoom doesn't fit the region
1522 precisely to the screen.
1525 GdkScreen* screen = gdk_screen_get_default ();
1526 gint pixwidth = gdk_screen_get_width (screen);
1527 gint mmwidth = gdk_screen_get_width_mm (screen);
1528 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1529 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1531 if ((start == 0 && end == 0) || end < start) {
1535 framepos_t range = end - start;
1536 double new_fpp = (double) range / (double) _visible_canvas_width;
1537 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1539 if (start > extra_samples) {
1540 start -= extra_samples;
1545 if (max_framepos - extra_samples > end) {
1546 end += extra_samples;
1551 /* if we're zooming on both axes we need to save track heights etc.
1554 undo_visual_stack.push_back (current_visual_state (both_axes));
1556 PBD::Unwinder<bool> nsv (no_save_visual, true);
1558 temporal_zoom_by_frame (start, end);
1561 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1563 /* set visible track heights appropriately */
1565 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1566 (*t)->set_height (per_track_height);
1569 /* hide irrelevant tracks */
1571 _routes->suspend_redisplay ();
1573 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1574 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1575 hide_track_in_display (*i);
1579 _routes->resume_redisplay ();
1581 vertical_adjustment.set_value (0.0);
1584 redo_visual_stack.push_back (current_visual_state (both_axes));
1588 Editor::zoom_to_region (bool both_axes)
1590 temporal_zoom_region (both_axes);
1594 Editor::temporal_zoom_selection ()
1596 if (!selection) return;
1598 if (selection->time.empty()) {
1602 framepos_t start = selection->time[clicked_selection].start;
1603 framepos_t end = selection->time[clicked_selection].end;
1605 temporal_zoom_by_frame (start, end);
1609 Editor::temporal_zoom_session ()
1611 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1614 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1615 double s = _session->current_start_frame() - l * 0.01;
1619 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1620 temporal_zoom_by_frame (framecnt_t (s), e);
1625 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1627 if (!_session) return;
1629 if ((start == 0 && end == 0) || end < start) {
1633 framepos_t range = end - start;
1635 double const new_fpp = (double) range / (double) _visible_canvas_width;
1637 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1638 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1639 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1641 if (new_leftmost > middle) {
1645 if (new_leftmost < 0) {
1649 reposition_and_zoom (new_leftmost, new_fpp);
1653 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1658 double range_before = frame - leftmost_frame;
1661 new_fpp = samples_per_pixel;
1664 new_fpp *= 1.61803399;
1665 range_before *= 1.61803399;
1667 new_fpp = max(1.0,(new_fpp/1.61803399));
1668 range_before /= 1.61803399;
1671 if (new_fpp == samples_per_pixel) {
1675 framepos_t new_leftmost = frame - (framepos_t)range_before;
1677 if (new_leftmost > frame) {
1681 if (new_leftmost < 0) {
1685 reposition_and_zoom (new_leftmost, new_fpp);
1690 Editor::choose_new_marker_name(string &name) {
1692 if (!Config->get_name_new_markers()) {
1693 /* don't prompt user for a new name */
1697 ArdourPrompter dialog (true);
1699 dialog.set_prompt (_("New Name:"));
1701 dialog.set_title (_("New Location Marker"));
1703 dialog.set_name ("MarkNameWindow");
1704 dialog.set_size_request (250, -1);
1705 dialog.set_position (Gtk::WIN_POS_MOUSE);
1707 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1708 dialog.set_initial_text (name);
1712 switch (dialog.run ()) {
1713 case RESPONSE_ACCEPT:
1719 dialog.get_result(name);
1726 Editor::add_location_from_selection ()
1730 if (selection->time.empty()) {
1734 if (_session == 0 || clicked_axisview == 0) {
1738 framepos_t start = selection->time[clicked_selection].start;
1739 framepos_t end = selection->time[clicked_selection].end;
1741 _session->locations()->next_available_name(rangename,"selection");
1742 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1744 _session->begin_reversible_command (_("add marker"));
1745 XMLNode &before = _session->locations()->get_state();
1746 _session->locations()->add (location, true);
1747 XMLNode &after = _session->locations()->get_state();
1748 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1749 _session->commit_reversible_command ();
1753 Editor::add_location_mark (framepos_t where)
1757 select_new_marker = true;
1759 _session->locations()->next_available_name(markername,"mark");
1760 if (!choose_new_marker_name(markername)) {
1763 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1764 _session->begin_reversible_command (_("add marker"));
1765 XMLNode &before = _session->locations()->get_state();
1766 _session->locations()->add (location, true);
1767 XMLNode &after = _session->locations()->get_state();
1768 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1769 _session->commit_reversible_command ();
1773 Editor::add_location_from_playhead_cursor ()
1775 add_location_mark (_session->audible_frame());
1778 /** Add a range marker around each selected region */
1780 Editor::add_locations_from_region ()
1782 RegionSelection rs = get_regions_from_selection_and_entered ();
1788 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1789 XMLNode &before = _session->locations()->get_state();
1791 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1793 boost::shared_ptr<Region> region = (*i)->region ();
1795 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1797 _session->locations()->add (location, true);
1800 XMLNode &after = _session->locations()->get_state();
1801 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1802 _session->commit_reversible_command ();
1805 /** Add a single range marker around all selected regions */
1807 Editor::add_location_from_region ()
1809 RegionSelection rs = get_regions_from_selection_and_entered ();
1815 _session->begin_reversible_command (_("add marker"));
1816 XMLNode &before = _session->locations()->get_state();
1820 if (rs.size() > 1) {
1821 _session->locations()->next_available_name(markername, "regions");
1823 RegionView* rv = *(rs.begin());
1824 boost::shared_ptr<Region> region = rv->region();
1825 markername = region->name();
1828 if (!choose_new_marker_name(markername)) {
1832 // single range spanning all selected
1833 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1834 _session->locations()->add (location, true);
1836 XMLNode &after = _session->locations()->get_state();
1837 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1838 _session->commit_reversible_command ();
1844 Editor::jump_forward_to_mark ()
1850 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
1856 _session->request_locate (pos, _session->transport_rolling());
1860 Editor::jump_backward_to_mark ()
1866 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
1872 _session->request_locate (pos, _session->transport_rolling());
1878 framepos_t const pos = _session->audible_frame ();
1881 _session->locations()->next_available_name (markername, "mark");
1883 if (!choose_new_marker_name (markername)) {
1887 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1891 Editor::clear_markers ()
1894 _session->begin_reversible_command (_("clear markers"));
1895 XMLNode &before = _session->locations()->get_state();
1896 _session->locations()->clear_markers ();
1897 XMLNode &after = _session->locations()->get_state();
1898 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1899 _session->commit_reversible_command ();
1904 Editor::clear_ranges ()
1907 _session->begin_reversible_command (_("clear ranges"));
1908 XMLNode &before = _session->locations()->get_state();
1910 Location * looploc = _session->locations()->auto_loop_location();
1911 Location * punchloc = _session->locations()->auto_punch_location();
1912 Location * sessionloc = _session->locations()->session_range_location();
1914 _session->locations()->clear_ranges ();
1916 if (looploc) _session->locations()->add (looploc);
1917 if (punchloc) _session->locations()->add (punchloc);
1918 if (sessionloc) _session->locations()->add (sessionloc);
1920 XMLNode &after = _session->locations()->get_state();
1921 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1922 _session->commit_reversible_command ();
1927 Editor::clear_locations ()
1929 _session->begin_reversible_command (_("clear locations"));
1930 XMLNode &before = _session->locations()->get_state();
1931 _session->locations()->clear ();
1932 XMLNode &after = _session->locations()->get_state();
1933 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1934 _session->commit_reversible_command ();
1935 _session->locations()->clear ();
1939 Editor::unhide_markers ()
1941 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1942 Location *l = (*i).first;
1943 if (l->is_hidden() && l->is_mark()) {
1944 l->set_hidden(false, this);
1950 Editor::unhide_ranges ()
1952 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1953 Location *l = (*i).first;
1954 if (l->is_hidden() && l->is_range_marker()) {
1955 l->set_hidden(false, this);
1960 /* INSERT/REPLACE */
1963 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1967 RouteTimeAxisView *rtv = 0;
1968 boost::shared_ptr<Playlist> playlist;
1971 event.type = GDK_BUTTON_RELEASE;
1975 where = window_event_frame (&event, &cx, &cy);
1977 if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) {
1978 /* clearly outside canvas area */
1982 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1983 if (tv.first == 0) {
1987 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1991 if ((playlist = rtv->playlist()) == 0) {
1997 begin_reversible_command (_("insert dragged region"));
1998 playlist->clear_changes ();
1999 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2000 _session->add_command(new StatefulDiffCommand (playlist));
2001 commit_reversible_command ();
2005 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2008 RouteTimeAxisView *dest_rtv = 0;
2009 RouteTimeAxisView *source_rtv = 0;
2012 event.type = GDK_BUTTON_RELEASE;
2016 window_event_frame (&event, &cx, &cy);
2018 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2019 if (tv.first == 0) {
2023 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2027 /* use this drag source to add underlay to a track. But we really don't care
2028 about the Route, only the view of the route, so find it first */
2029 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2030 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2034 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2035 dest_rtv->add_underlay(source_rtv->view());
2042 Editor::insert_region_list_selection (float times)
2044 RouteTimeAxisView *tv = 0;
2045 boost::shared_ptr<Playlist> playlist;
2047 if (clicked_routeview != 0) {
2048 tv = clicked_routeview;
2049 } else if (!selection->tracks.empty()) {
2050 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2053 } else if (entered_track != 0) {
2054 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2061 if ((playlist = tv->playlist()) == 0) {
2065 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2070 begin_reversible_command (_("insert region"));
2071 playlist->clear_changes ();
2072 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2073 _session->add_command(new StatefulDiffCommand (playlist));
2074 commit_reversible_command ();
2077 /* BUILT-IN EFFECTS */
2080 Editor::reverse_selection ()
2085 /* GAIN ENVELOPE EDITING */
2088 Editor::edit_envelope ()
2095 Editor::transition_to_rolling (bool fwd)
2101 if (_session->config.get_external_sync()) {
2102 switch (Config->get_sync_source()) {
2106 /* transport controlled by the master */
2111 if (_session->is_auditioning()) {
2112 _session->cancel_audition ();
2116 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2120 Editor::play_from_start ()
2122 _session->request_locate (_session->current_start_frame(), true);
2126 Editor::play_from_edit_point ()
2128 _session->request_locate (get_preferred_edit_position(), true);
2132 Editor::play_from_edit_point_and_return ()
2134 framepos_t start_frame;
2135 framepos_t return_frame;
2137 start_frame = get_preferred_edit_position (true);
2139 if (_session->transport_rolling()) {
2140 _session->request_locate (start_frame, false);
2144 /* don't reset the return frame if its already set */
2146 if ((return_frame = _session->requested_return_frame()) < 0) {
2147 return_frame = _session->audible_frame();
2150 if (start_frame >= 0) {
2151 _session->request_roll_at_and_return (start_frame, return_frame);
2156 Editor::play_selection ()
2158 if (selection->time.empty()) {
2162 _session->request_play_range (&selection->time, true);
2166 Editor::get_preroll ()
2168 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2173 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2175 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2178 location -= get_preroll();
2180 //don't try to locate before the beginning of time
2184 //if follow_playhead is on, keep the playhead on the screen
2185 if ( _follow_playhead )
2186 if ( location < leftmost_frame )
2187 location = leftmost_frame;
2189 _session->request_locate( location );
2193 Editor::play_with_preroll ()
2195 if (selection->time.empty()) {
2198 framepos_t preroll = get_preroll();
2200 framepos_t start = 0;
2201 if (selection->time[clicked_selection].start > preroll)
2202 start = selection->time[clicked_selection].start - preroll;
2204 framepos_t end = selection->time[clicked_selection].end + preroll;
2206 AudioRange ar (start, end, 0);
2207 list<AudioRange> lar;
2210 _session->request_play_range (&lar, true);
2215 Editor::play_location (Location& location)
2217 if (location.start() <= location.end()) {
2221 _session->request_bounded_roll (location.start(), location.end());
2225 Editor::loop_location (Location& location)
2227 if (location.start() <= location.end()) {
2233 if ((tll = transport_loop_location()) != 0) {
2234 tll->set (location.start(), location.end());
2236 // enable looping, reposition and start rolling
2237 _session->request_play_loop (true);
2238 _session->request_locate (tll->start(), true);
2243 Editor::do_layer_operation (LayerOperation op)
2245 if (selection->regions.empty ()) {
2249 bool const multiple = selection->regions.size() > 1;
2253 begin_reversible_command (_("raise regions"));
2255 begin_reversible_command (_("raise region"));
2261 begin_reversible_command (_("raise regions to top"));
2263 begin_reversible_command (_("raise region to top"));
2269 begin_reversible_command (_("lower regions"));
2271 begin_reversible_command (_("lower region"));
2277 begin_reversible_command (_("lower regions to bottom"));
2279 begin_reversible_command (_("lower region"));
2284 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2285 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2286 (*i)->clear_owned_changes ();
2289 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2290 boost::shared_ptr<Region> r = (*i)->region ();
2302 r->lower_to_bottom ();
2306 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2307 vector<Command*> cmds;
2309 _session->add_commands (cmds);
2312 commit_reversible_command ();
2316 Editor::raise_region ()
2318 do_layer_operation (Raise);
2322 Editor::raise_region_to_top ()
2324 do_layer_operation (RaiseToTop);
2328 Editor::lower_region ()
2330 do_layer_operation (Lower);
2334 Editor::lower_region_to_bottom ()
2336 do_layer_operation (LowerToBottom);
2339 /** Show the region editor for the selected regions */
2341 Editor::show_region_properties ()
2343 selection->foreach_regionview (&RegionView::show_region_editor);
2346 /** Show the midi list editor for the selected MIDI regions */
2348 Editor::show_midi_list_editor ()
2350 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2354 Editor::rename_region ()
2356 RegionSelection rs = get_regions_from_selection_and_entered ();
2362 ArdourDialog d (*this, _("Rename Region"), true, false);
2364 Label label (_("New name:"));
2367 hbox.set_spacing (6);
2368 hbox.pack_start (label, false, false);
2369 hbox.pack_start (entry, true, true);
2371 d.get_vbox()->set_border_width (12);
2372 d.get_vbox()->pack_start (hbox, false, false);
2374 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2375 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2377 d.set_size_request (300, -1);
2379 entry.set_text (rs.front()->region()->name());
2380 entry.select_region (0, -1);
2382 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2388 int const ret = d.run();
2392 if (ret != RESPONSE_OK) {
2396 std::string str = entry.get_text();
2397 strip_whitespace_edges (str);
2399 rs.front()->region()->set_name (str);
2400 _regions->redisplay ();
2405 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2407 if (_session->is_auditioning()) {
2408 _session->cancel_audition ();
2411 // note: some potential for creativity here, because region doesn't
2412 // have to belong to the playlist that Route is handling
2414 // bool was_soloed = route.soloed();
2416 route.set_solo (true, this);
2418 _session->request_bounded_roll (region->position(), region->position() + region->length());
2420 /* XXX how to unset the solo state ? */
2423 /** Start an audition of the first selected region */
2425 Editor::play_edit_range ()
2427 framepos_t start, end;
2429 if (get_edit_op_range (start, end)) {
2430 _session->request_bounded_roll (start, end);
2435 Editor::play_selected_region ()
2437 framepos_t start = max_framepos;
2440 RegionSelection rs = get_regions_from_selection_and_entered ();
2446 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2447 if ((*i)->region()->position() < start) {
2448 start = (*i)->region()->position();
2450 if ((*i)->region()->last_frame() + 1 > end) {
2451 end = (*i)->region()->last_frame() + 1;
2455 _session->request_bounded_roll (start, end);
2459 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2461 _session->audition_region (region);
2465 Editor::region_from_selection ()
2467 if (clicked_axisview == 0) {
2471 if (selection->time.empty()) {
2475 framepos_t start = selection->time[clicked_selection].start;
2476 framepos_t end = selection->time[clicked_selection].end;
2478 TrackViewList tracks = get_tracks_for_range_action ();
2480 framepos_t selection_cnt = end - start + 1;
2482 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2483 boost::shared_ptr<Region> current;
2484 boost::shared_ptr<Playlist> pl;
2485 framepos_t internal_start;
2488 if ((pl = (*i)->playlist()) == 0) {
2492 if ((current = pl->top_region_at (start)) == 0) {
2496 internal_start = start - current->position();
2497 RegionFactory::region_name (new_name, current->name(), true);
2501 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2502 plist.add (ARDOUR::Properties::length, selection_cnt);
2503 plist.add (ARDOUR::Properties::name, new_name);
2504 plist.add (ARDOUR::Properties::layer, 0);
2506 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2511 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2513 if (selection->time.empty() || selection->tracks.empty()) {
2517 framepos_t start = selection->time[clicked_selection].start;
2518 framepos_t end = selection->time[clicked_selection].end;
2520 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2521 sort_track_selection (ts);
2523 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2524 boost::shared_ptr<Region> current;
2525 boost::shared_ptr<Playlist> playlist;
2526 framepos_t internal_start;
2529 if ((playlist = (*i)->playlist()) == 0) {
2533 if ((current = playlist->top_region_at(start)) == 0) {
2537 internal_start = start - current->position();
2538 RegionFactory::region_name (new_name, current->name(), true);
2542 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2543 plist.add (ARDOUR::Properties::length, end - start + 1);
2544 plist.add (ARDOUR::Properties::name, new_name);
2546 new_regions.push_back (RegionFactory::create (current, plist));
2551 Editor::split_multichannel_region ()
2553 RegionSelection rs = get_regions_from_selection_and_entered ();
2559 vector< boost::shared_ptr<Region> > v;
2561 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2562 (*x)->region()->separate_by_channel (*_session, v);
2567 Editor::new_region_from_selection ()
2569 region_from_selection ();
2570 cancel_selection ();
2574 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2576 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2577 case Evoral::OverlapNone:
2585 * - selected tracks, or if there are none...
2586 * - tracks containing selected regions, or if there are none...
2591 Editor::get_tracks_for_range_action () const
2595 if (selection->tracks.empty()) {
2597 /* use tracks with selected regions */
2599 RegionSelection rs = selection->regions;
2601 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2602 TimeAxisView* tv = &(*i)->get_time_axis_view();
2604 if (!t.contains (tv)) {
2610 /* no regions and no tracks: use all tracks */
2616 t = selection->tracks;
2619 return t.filter_to_unique_playlists();
2623 Editor::separate_regions_between (const TimeSelection& ts)
2625 bool in_command = false;
2626 boost::shared_ptr<Playlist> playlist;
2627 RegionSelection new_selection;
2629 TrackViewList tmptracks = get_tracks_for_range_action ();
2630 sort_track_selection (tmptracks);
2632 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2634 RouteTimeAxisView* rtv;
2636 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2638 if (rtv->is_track()) {
2640 /* no edits to destructive tracks */
2642 if (rtv->track()->destructive()) {
2646 if ((playlist = rtv->playlist()) != 0) {
2648 playlist->clear_changes ();
2650 /* XXX need to consider musical time selections here at some point */
2652 double speed = rtv->track()->speed();
2655 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2657 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2658 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2660 latest_regionviews.clear ();
2662 playlist->partition ((framepos_t)((*t).start * speed),
2663 (framepos_t)((*t).end * speed), false);
2667 if (!latest_regionviews.empty()) {
2669 rtv->view()->foreach_regionview (sigc::bind (
2670 sigc::ptr_fun (add_if_covered),
2671 &(*t), &new_selection));
2674 begin_reversible_command (_("separate"));
2678 /* pick up changes to existing regions */
2680 vector<Command*> cmds;
2681 playlist->rdiff (cmds);
2682 _session->add_commands (cmds);
2684 /* pick up changes to the playlist itself (adds/removes)
2687 _session->add_command(new StatefulDiffCommand (playlist));
2696 selection->set (new_selection);
2697 set_mouse_mode (MouseObject);
2699 commit_reversible_command ();
2703 struct PlaylistState {
2704 boost::shared_ptr<Playlist> playlist;
2708 /** Take tracks from get_tracks_for_range_action and cut any regions
2709 * on those tracks so that the tracks are empty over the time
2713 Editor::separate_region_from_selection ()
2715 /* preferentially use *all* ranges in the time selection if we're in range mode
2716 to allow discontiguous operation, since get_edit_op_range() currently
2717 returns a single range.
2720 if (!selection->time.empty()) {
2722 separate_regions_between (selection->time);
2729 if (get_edit_op_range (start, end)) {
2731 AudioRange ar (start, end, 1);
2735 separate_regions_between (ts);
2741 Editor::separate_region_from_punch ()
2743 Location* loc = _session->locations()->auto_punch_location();
2745 separate_regions_using_location (*loc);
2750 Editor::separate_region_from_loop ()
2752 Location* loc = _session->locations()->auto_loop_location();
2754 separate_regions_using_location (*loc);
2759 Editor::separate_regions_using_location (Location& loc)
2761 if (loc.is_mark()) {
2765 AudioRange ar (loc.start(), loc.end(), 1);
2770 separate_regions_between (ts);
2773 /** Separate regions under the selected region */
2775 Editor::separate_under_selected_regions ()
2777 vector<PlaylistState> playlists;
2781 rs = get_regions_from_selection_and_entered();
2783 if (!_session || rs.empty()) {
2787 begin_reversible_command (_("separate region under"));
2789 list<boost::shared_ptr<Region> > regions_to_remove;
2791 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2792 // we can't just remove the region(s) in this loop because
2793 // this removes them from the RegionSelection, and they thus
2794 // disappear from underneath the iterator, and the ++i above
2795 // SEGVs in a puzzling fashion.
2797 // so, first iterate over the regions to be removed from rs and
2798 // add them to the regions_to_remove list, and then
2799 // iterate over the list to actually remove them.
2801 regions_to_remove.push_back ((*i)->region());
2804 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2806 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2809 // is this check necessary?
2813 vector<PlaylistState>::iterator i;
2815 //only take state if this is a new playlist.
2816 for (i = playlists.begin(); i != playlists.end(); ++i) {
2817 if ((*i).playlist == playlist) {
2822 if (i == playlists.end()) {
2824 PlaylistState before;
2825 before.playlist = playlist;
2826 before.before = &playlist->get_state();
2828 playlist->freeze ();
2829 playlists.push_back(before);
2832 //Partition on the region bounds
2833 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2835 //Re-add region that was just removed due to the partition operation
2836 playlist->add_region( (*rl), (*rl)->first_frame() );
2839 vector<PlaylistState>::iterator pl;
2841 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2842 (*pl).playlist->thaw ();
2843 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2846 commit_reversible_command ();
2850 Editor::crop_region_to_selection ()
2852 if (!selection->time.empty()) {
2854 crop_region_to (selection->time.start(), selection->time.end_frame());
2861 if (get_edit_op_range (start, end)) {
2862 crop_region_to (start, end);
2869 Editor::crop_region_to (framepos_t start, framepos_t end)
2871 vector<boost::shared_ptr<Playlist> > playlists;
2872 boost::shared_ptr<Playlist> playlist;
2875 if (selection->tracks.empty()) {
2876 ts = track_views.filter_to_unique_playlists();
2878 ts = selection->tracks.filter_to_unique_playlists ();
2881 sort_track_selection (ts);
2883 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2885 RouteTimeAxisView* rtv;
2887 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2889 boost::shared_ptr<Track> t = rtv->track();
2891 if (t != 0 && ! t->destructive()) {
2893 if ((playlist = rtv->playlist()) != 0) {
2894 playlists.push_back (playlist);
2900 if (playlists.empty()) {
2904 framepos_t the_start;
2908 begin_reversible_command (_("trim to selection"));
2910 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2912 boost::shared_ptr<Region> region;
2916 if ((region = (*i)->top_region_at(the_start)) == 0) {
2920 /* now adjust lengths to that we do the right thing
2921 if the selection extends beyond the region
2924 the_start = max (the_start, (framepos_t) region->position());
2925 if (max_framepos - the_start < region->length()) {
2926 the_end = the_start + region->length() - 1;
2928 the_end = max_framepos;
2930 the_end = min (end, the_end);
2931 cnt = the_end - the_start + 1;
2933 region->clear_changes ();
2934 region->trim_to (the_start, cnt);
2935 _session->add_command (new StatefulDiffCommand (region));
2938 commit_reversible_command ();
2942 Editor::region_fill_track ()
2944 RegionSelection rs = get_regions_from_selection_and_entered ();
2946 if (!_session || rs.empty()) {
2950 framepos_t const end = _session->current_end_frame ();
2952 begin_reversible_command (Operations::region_fill);
2954 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2956 boost::shared_ptr<Region> region ((*i)->region());
2958 boost::shared_ptr<Playlist> pl = region->playlist();
2960 if (end <= region->last_frame()) {
2964 double times = (double) (end - region->last_frame()) / (double) region->length();
2970 pl->clear_changes ();
2971 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2972 _session->add_command (new StatefulDiffCommand (pl));
2975 commit_reversible_command ();
2979 Editor::region_fill_selection ()
2981 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2985 if (selection->time.empty()) {
2989 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2994 framepos_t start = selection->time[clicked_selection].start;
2995 framepos_t end = selection->time[clicked_selection].end;
2997 boost::shared_ptr<Playlist> playlist;
2999 if (selection->tracks.empty()) {
3003 framepos_t selection_length = end - start;
3004 float times = (float)selection_length / region->length();
3006 begin_reversible_command (Operations::fill_selection);
3008 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3010 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3012 if ((playlist = (*i)->playlist()) == 0) {
3016 playlist->clear_changes ();
3017 playlist->add_region (RegionFactory::create (region, true), start, times);
3018 _session->add_command (new StatefulDiffCommand (playlist));
3021 commit_reversible_command ();
3025 Editor::set_region_sync_position ()
3027 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3031 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3033 bool in_command = false;
3035 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3037 if (!(*r)->region()->covers (where)) {
3041 boost::shared_ptr<Region> region ((*r)->region());
3044 begin_reversible_command (_("set sync point"));
3048 region->clear_changes ();
3049 region->set_sync_position (where);
3050 _session->add_command(new StatefulDiffCommand (region));
3054 commit_reversible_command ();
3058 /** Remove the sync positions of the selection */
3060 Editor::remove_region_sync ()
3062 RegionSelection rs = get_regions_from_selection_and_entered ();
3068 begin_reversible_command (_("remove region sync"));
3070 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3072 (*i)->region()->clear_changes ();
3073 (*i)->region()->clear_sync_position ();
3074 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3077 commit_reversible_command ();
3081 Editor::naturalize_region ()
3083 RegionSelection rs = get_regions_from_selection_and_entered ();
3089 if (rs.size() > 1) {
3090 begin_reversible_command (_("move regions to original position"));
3092 begin_reversible_command (_("move region to original position"));
3095 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3096 (*i)->region()->clear_changes ();
3097 (*i)->region()->move_to_natural_position ();
3098 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3101 commit_reversible_command ();
3105 Editor::align_regions (RegionPoint what)
3107 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3113 begin_reversible_command (_("align selection"));
3115 framepos_t const position = get_preferred_edit_position ();
3117 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3118 align_region_internal ((*i)->region(), what, position);
3121 commit_reversible_command ();
3124 struct RegionSortByTime {
3125 bool operator() (const RegionView* a, const RegionView* b) {
3126 return a->region()->position() < b->region()->position();
3131 Editor::align_regions_relative (RegionPoint point)
3133 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3139 framepos_t const position = get_preferred_edit_position ();
3141 framepos_t distance = 0;
3145 list<RegionView*> sorted;
3146 rs.by_position (sorted);
3148 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3153 if (position > r->position()) {
3154 distance = position - r->position();
3156 distance = r->position() - position;
3162 if (position > r->last_frame()) {
3163 distance = position - r->last_frame();
3164 pos = r->position() + distance;
3166 distance = r->last_frame() - position;
3167 pos = r->position() - distance;
3173 pos = r->adjust_to_sync (position);
3174 if (pos > r->position()) {
3175 distance = pos - r->position();
3177 distance = r->position() - pos;
3183 if (pos == r->position()) {
3187 begin_reversible_command (_("align selection (relative)"));
3189 /* move first one specially */
3191 r->clear_changes ();
3192 r->set_position (pos);
3193 _session->add_command(new StatefulDiffCommand (r));
3195 /* move rest by the same amount */
3199 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3201 boost::shared_ptr<Region> region ((*i)->region());
3203 region->clear_changes ();
3206 region->set_position (region->position() + distance);
3208 region->set_position (region->position() - distance);
3211 _session->add_command(new StatefulDiffCommand (region));
3215 commit_reversible_command ();
3219 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3221 begin_reversible_command (_("align region"));
3222 align_region_internal (region, point, position);
3223 commit_reversible_command ();
3227 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3229 region->clear_changes ();
3233 region->set_position (region->adjust_to_sync (position));
3237 if (position > region->length()) {
3238 region->set_position (position - region->length());
3243 region->set_position (position);
3247 _session->add_command(new StatefulDiffCommand (region));
3251 Editor::trim_region_front ()
3257 Editor::trim_region_back ()
3259 trim_region (false);
3263 Editor::trim_region (bool front)
3265 framepos_t where = get_preferred_edit_position();
3266 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3272 begin_reversible_command (front ? _("trim front") : _("trim back"));
3274 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3275 if (!(*i)->region()->locked()) {
3277 (*i)->region()->clear_changes ();
3280 (*i)->region()->trim_front (where);
3281 maybe_locate_with_edit_preroll ( where );
3283 (*i)->region()->trim_end (where);
3284 maybe_locate_with_edit_preroll ( where );
3287 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3291 commit_reversible_command ();
3294 /** Trim the end of the selected regions to the position of the edit cursor */
3296 Editor::trim_region_to_loop ()
3298 Location* loc = _session->locations()->auto_loop_location();
3302 trim_region_to_location (*loc, _("trim to loop"));
3306 Editor::trim_region_to_punch ()
3308 Location* loc = _session->locations()->auto_punch_location();
3312 trim_region_to_location (*loc, _("trim to punch"));
3316 Editor::trim_region_to_location (const Location& loc, const char* str)
3318 RegionSelection rs = get_regions_from_selection_and_entered ();
3320 begin_reversible_command (str);
3322 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3323 RegionView* rv = (*x);
3325 /* require region to span proposed trim */
3326 switch (rv->region()->coverage (loc.start(), loc.end())) {
3327 case Evoral::OverlapInternal:
3333 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3342 if (tav->track() != 0) {
3343 speed = tav->track()->speed();
3346 start = session_frame_to_track_frame (loc.start(), speed);
3347 end = session_frame_to_track_frame (loc.end(), speed);
3349 rv->region()->clear_changes ();
3350 rv->region()->trim_to (start, (end - start));
3351 _session->add_command(new StatefulDiffCommand (rv->region()));
3354 commit_reversible_command ();
3358 Editor::trim_region_to_previous_region_end ()
3360 return trim_to_region(false);
3364 Editor::trim_region_to_next_region_start ()
3366 return trim_to_region(true);
3370 Editor::trim_to_region(bool forward)
3372 RegionSelection rs = get_regions_from_selection_and_entered ();
3374 begin_reversible_command (_("trim to region"));
3376 boost::shared_ptr<Region> next_region;
3378 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3380 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3386 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3394 if (atav->track() != 0) {
3395 speed = atav->track()->speed();
3399 boost::shared_ptr<Region> region = arv->region();
3400 boost::shared_ptr<Playlist> playlist (region->playlist());
3402 region->clear_changes ();
3406 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3412 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3413 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3417 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3423 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3425 arv->region_changed (ARDOUR::bounds_change);
3428 _session->add_command(new StatefulDiffCommand (region));
3431 commit_reversible_command ();
3435 Editor::unfreeze_route ()
3437 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3441 clicked_routeview->track()->unfreeze ();
3445 Editor::_freeze_thread (void* arg)
3447 return static_cast<Editor*>(arg)->freeze_thread ();
3451 Editor::freeze_thread ()
3453 /* create event pool because we may need to talk to the session */
3454 SessionEvent::create_per_thread_pool ("freeze events", 64);
3455 /* create per-thread buffers for process() tree to use */
3456 current_interthread_info->process_thread.get_buffers ();
3457 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3458 current_interthread_info->done = true;
3459 current_interthread_info->process_thread.drop_buffers();
3464 Editor::freeze_route ()
3470 /* stop transport before we start. this is important */
3472 _session->request_transport_speed (0.0);
3474 /* wait for just a little while, because the above call is asynchronous */
3476 Glib::usleep (250000);
3478 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3482 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3484 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3485 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3487 d.set_title (_("Cannot freeze"));
3492 if (clicked_routeview->track()->has_external_redirects()) {
3493 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"
3494 "Freezing will only process the signal as far as the first send/insert/return."),
3495 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3497 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3498 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3499 d.set_title (_("Freeze Limits"));
3501 int response = d.run ();
3504 case Gtk::RESPONSE_CANCEL:
3511 InterThreadInfo itt;
3512 current_interthread_info = &itt;
3514 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3516 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3518 set_canvas_cursor (_cursors->wait);
3520 while (!itt.done && !itt.cancel) {
3521 gtk_main_iteration ();
3524 current_interthread_info = 0;
3525 set_canvas_cursor (current_canvas_cursor);
3529 Editor::bounce_range_selection (bool replace, bool enable_processing)
3531 if (selection->time.empty()) {
3535 TrackSelection views = selection->tracks;
3537 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3539 if (enable_processing) {
3541 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3543 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3545 _("You can't perform this operation because the processing of the signal "
3546 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3547 "You can do this without processing, which is a different operation.")
3549 d.set_title (_("Cannot bounce"));
3556 framepos_t start = selection->time[clicked_selection].start;
3557 framepos_t end = selection->time[clicked_selection].end;
3558 framepos_t cnt = end - start + 1;
3560 begin_reversible_command (_("bounce range"));
3562 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3564 RouteTimeAxisView* rtv;
3566 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3570 boost::shared_ptr<Playlist> playlist;
3572 if ((playlist = rtv->playlist()) == 0) {
3576 InterThreadInfo itt;
3578 playlist->clear_changes ();
3579 playlist->clear_owned_changes ();
3581 boost::shared_ptr<Region> r;
3583 if (enable_processing) {
3584 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3586 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3594 list<AudioRange> ranges;
3595 ranges.push_back (AudioRange (start, start+cnt, 0));
3596 playlist->cut (ranges); // discard result
3597 playlist->add_region (r, start);
3600 vector<Command*> cmds;
3601 playlist->rdiff (cmds);
3602 _session->add_commands (cmds);
3604 _session->add_command (new StatefulDiffCommand (playlist));
3607 commit_reversible_command ();
3610 /** Delete selected regions, automation points or a time range */
3617 /** Cut selected regions, automation points or a time range */
3624 /** Copy selected regions, automation points or a time range */
3632 /** @return true if a Cut, Copy or Clear is possible */
3634 Editor::can_cut_copy () const
3636 switch (effective_mouse_mode()) {
3639 if (!selection->regions.empty() || !selection->points.empty()) {
3645 if (!selection->time.empty()) {
3658 /** Cut, copy or clear selected regions, automation points or a time range.
3659 * @param op Operation (Cut, Copy or Clear)
3662 Editor::cut_copy (CutCopyOp op)
3664 /* only cancel selection if cut/copy is successful.*/
3670 opname = _("delete");
3679 opname = _("clear");
3683 /* if we're deleting something, and the mouse is still pressed,
3684 the thing we started a drag for will be gone when we release
3685 the mouse button(s). avoid this. see part 2 at the end of
3689 if (op == Delete || op == Cut || op == Clear) {
3690 if (_drags->active ()) {
3695 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3696 cut_buffer->clear ();
3698 if (entered_marker) {
3700 /* cut/delete op while pointing at a marker */
3703 Location* loc = find_location_from_marker (entered_marker, ignored);
3705 if (_session && loc) {
3706 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3713 if (internal_editing()) {
3715 switch (effective_mouse_mode()) {
3728 /* we only want to cut regions if some are selected */
3730 if (!selection->regions.empty()) {
3731 rs = selection->regions;
3734 switch (effective_mouse_mode()) {
3737 //find regions's gain line
3738 AudioRegionView *rview = dynamic_cast<AudioRegionView*>(clicked_regionview);
3739 AutomationTimeAxisView *tview = dynamic_cast<AutomationTimeAxisView*>(clicked_trackview);
3741 AudioRegionGainLine *line = rview->get_gain_line();
3744 //cut region gain points in the selection
3745 AutomationList& alist (line->the_list());
3746 XMLNode &before = alist.get_state();
3747 AutomationList* what_we_got = 0;
3748 if ((what_we_got = alist.cut (selection->time.front().start - rview->audio_region()->position(), selection->time.front().end - rview->audio_region()->position())) != 0) {
3749 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3754 rview->set_envelope_visible(true);
3755 rview->audio_region()->set_envelope_active(true);
3758 AutomationLine *line = *(tview->lines.begin());
3761 //cut auto points in the selection
3762 AutomationList& alist (line->the_list());
3763 XMLNode &before = alist.get_state();
3764 AutomationList* what_we_got = 0;
3765 if ((what_we_got = alist.cut (selection->time.front().start, selection->time.front().end)) != 0) {
3766 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3776 if (!rs.empty() || !selection->points.empty()) {
3777 begin_reversible_command (opname + _(" objects"));
3780 cut_copy_regions (op, rs);
3782 if (op == Cut || op == Delete) {
3783 selection->clear_regions ();
3787 if (!selection->points.empty()) {
3788 cut_copy_points (op);
3790 if (op == Cut || op == Delete) {
3791 selection->clear_points ();
3795 commit_reversible_command ();
3799 if (selection->time.empty()) {
3800 framepos_t start, end;
3801 if (!get_edit_op_range (start, end)) {
3804 selection->set (start, end);
3807 begin_reversible_command (opname + _(" range"));
3808 cut_copy_ranges (op);
3809 commit_reversible_command ();
3811 if (op == Cut || op == Delete) {
3812 selection->clear_time ();
3822 if (op == Delete || op == Cut || op == Clear) {
3827 struct AutomationRecord {
3828 AutomationRecord () : state (0) {}
3829 AutomationRecord (XMLNode* s) : state (s) {}
3831 XMLNode* state; ///< state before any operation
3832 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3835 /** Cut, copy or clear selected automation points.
3836 * @param op Operation (Cut, Copy or Clear)
3839 Editor::cut_copy_points (CutCopyOp op)
3841 if (selection->points.empty ()) {
3845 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3846 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3848 /* Keep a record of the AutomationLists that we end up using in this operation */
3849 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3852 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3853 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3854 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3855 if (lists.find (al) == lists.end ()) {
3856 /* We haven't seen this list yet, so make a record for it. This includes
3857 taking a copy of its current state, in case this is needed for undo later.
3859 lists[al] = AutomationRecord (&al->get_state ());
3863 if (op == Cut || op == Copy) {
3864 /* This operation will involve putting things in the cut buffer, so create an empty
3865 ControlList for each of our source lists to put the cut buffer data in.
3867 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3868 i->second.copy = i->first->create (i->first->parameter ());
3871 /* Add all selected points to the relevant copy ControlLists */
3872 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3873 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3874 AutomationList::const_iterator j = (*i)->model ();
3875 lists[al].copy->add ((*j)->when, (*j)->value);
3878 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3879 /* Correct this copy list so that it starts at time 0 */
3880 double const start = i->second.copy->front()->when;
3881 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3882 (*j)->when -= start;
3885 /* And add it to the cut buffer */
3886 cut_buffer->add (i->second.copy);
3890 if (op == Delete || op == Cut) {
3891 /* This operation needs to remove things from the main AutomationList, so do that now */
3893 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3894 i->first->freeze ();
3897 /* Remove each selected point from its AutomationList */
3898 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3899 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3900 al->erase ((*i)->model ());
3903 /* Thaw the lists and add undo records for them */
3904 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3905 boost::shared_ptr<AutomationList> al = i->first;
3907 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3912 /** Cut, copy or clear selected automation points.
3913 * @param op Operation (Cut, Copy or Clear)
3916 Editor::cut_copy_midi (CutCopyOp op)
3918 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3919 MidiRegionView* mrv = *i;
3920 mrv->cut_copy_clear (op);
3926 struct lt_playlist {
3927 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3928 return a.playlist < b.playlist;
3932 struct PlaylistMapping {
3934 boost::shared_ptr<Playlist> pl;
3936 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3939 /** Remove `clicked_regionview' */
3941 Editor::remove_clicked_region ()
3943 if (clicked_routeview == 0 || clicked_regionview == 0) {
3947 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3949 begin_reversible_command (_("remove region"));
3950 playlist->clear_changes ();
3951 playlist->clear_owned_changes ();
3952 playlist->remove_region (clicked_regionview->region());
3954 /* We might have removed regions, which alters other regions' layering_index,
3955 so we need to do a recursive diff here.
3957 vector<Command*> cmds;
3958 playlist->rdiff (cmds);
3959 _session->add_commands (cmds);
3961 _session->add_command(new StatefulDiffCommand (playlist));
3962 commit_reversible_command ();
3966 /** Remove the selected regions */
3968 Editor::remove_selected_regions ()
3970 RegionSelection rs = get_regions_from_selection_and_entered ();
3972 if (!_session || rs.empty()) {
3976 begin_reversible_command (_("remove region"));
3978 list<boost::shared_ptr<Region> > regions_to_remove;
3980 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3981 // we can't just remove the region(s) in this loop because
3982 // this removes them from the RegionSelection, and they thus
3983 // disappear from underneath the iterator, and the ++i above
3984 // SEGVs in a puzzling fashion.
3986 // so, first iterate over the regions to be removed from rs and
3987 // add them to the regions_to_remove list, and then
3988 // iterate over the list to actually remove them.
3990 regions_to_remove.push_back ((*i)->region());
3993 vector<boost::shared_ptr<Playlist> > playlists;
3995 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3997 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4000 // is this check necessary?
4004 /* get_regions_from_selection_and_entered() guarantees that
4005 the playlists involved are unique, so there is no need
4009 playlists.push_back (playlist);
4011 playlist->clear_changes ();
4012 playlist->clear_owned_changes ();
4013 playlist->freeze ();
4014 playlist->remove_region (*rl);
4017 vector<boost::shared_ptr<Playlist> >::iterator pl;
4019 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4022 /* We might have removed regions, which alters other regions' layering_index,
4023 so we need to do a recursive diff here.
4025 vector<Command*> cmds;
4026 (*pl)->rdiff (cmds);
4027 _session->add_commands (cmds);
4029 _session->add_command(new StatefulDiffCommand (*pl));
4032 commit_reversible_command ();
4035 /** Cut, copy or clear selected regions.
4036 * @param op Operation (Cut, Copy or Clear)
4039 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4041 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4042 a map when we want ordered access to both elements. i think.
4045 vector<PlaylistMapping> pmap;
4047 framepos_t first_position = max_framepos;
4049 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4050 FreezeList freezelist;
4052 /* get ordering correct before we cut/copy */
4054 rs.sort_by_position_and_track ();
4056 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4058 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4060 if (op == Cut || op == Clear || op == Delete) {
4061 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4064 FreezeList::iterator fl;
4066 // only take state if this is a new playlist.
4067 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4073 if (fl == freezelist.end()) {
4074 pl->clear_changes();
4075 pl->clear_owned_changes ();
4077 freezelist.insert (pl);
4082 TimeAxisView* tv = &(*x)->get_time_axis_view();
4083 vector<PlaylistMapping>::iterator z;
4085 for (z = pmap.begin(); z != pmap.end(); ++z) {
4086 if ((*z).tv == tv) {
4091 if (z == pmap.end()) {
4092 pmap.push_back (PlaylistMapping (tv));
4096 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4098 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4101 /* region not yet associated with a playlist (e.g. unfinished
4108 TimeAxisView& tv = (*x)->get_time_axis_view();
4109 boost::shared_ptr<Playlist> npl;
4110 RegionSelection::iterator tmp;
4117 vector<PlaylistMapping>::iterator z;
4119 for (z = pmap.begin(); z != pmap.end(); ++z) {
4120 if ((*z).tv == &tv) {
4125 assert (z != pmap.end());
4128 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4136 boost::shared_ptr<Region> r = (*x)->region();
4137 boost::shared_ptr<Region> _xx;
4143 pl->remove_region (r);
4147 _xx = RegionFactory::create (r);
4148 npl->add_region (_xx, r->position() - first_position);
4149 pl->remove_region (r);
4153 /* copy region before adding, so we're not putting same object into two different playlists */
4154 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4158 pl->remove_region (r);
4167 list<boost::shared_ptr<Playlist> > foo;
4169 /* the pmap is in the same order as the tracks in which selected regions occured */
4171 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4174 foo.push_back ((*i).pl);
4179 cut_buffer->set (foo);
4183 _last_cut_copy_source_track = 0;
4185 _last_cut_copy_source_track = pmap.front().tv;
4189 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4192 /* We might have removed regions, which alters other regions' layering_index,
4193 so we need to do a recursive diff here.
4195 vector<Command*> cmds;
4196 (*pl)->rdiff (cmds);
4197 _session->add_commands (cmds);
4199 _session->add_command (new StatefulDiffCommand (*pl));
4204 Editor::cut_copy_ranges (CutCopyOp op)
4206 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4208 /* Sort the track selection now, so that it if is used, the playlists
4209 selected by the calls below to cut_copy_clear are in the order that
4210 their tracks appear in the editor. This makes things like paste
4211 of ranges work properly.
4214 sort_track_selection (ts);
4217 if (!entered_track) {
4220 ts.push_back (entered_track);
4223 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4224 (*i)->cut_copy_clear (*selection, op);
4229 Editor::paste (float times, bool from_context)
4231 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4233 paste_internal (get_preferred_edit_position (false, from_context), times);
4237 Editor::mouse_paste ()
4242 if (!mouse_frame (where, ignored)) {
4247 paste_internal (where, 1);
4251 Editor::paste_internal (framepos_t position, float times)
4253 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4255 if (internal_editing()) {
4256 if (cut_buffer->midi_notes.empty()) {
4260 if (cut_buffer->empty()) {
4265 if (position == max_framepos) {
4266 position = get_preferred_edit_position();
4267 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4271 TrackViewList::iterator i;
4274 /* get everything in the correct order */
4276 if (_edit_point == Editing::EditAtMouse && entered_track) {
4277 /* With the mouse edit point, paste onto the track under the mouse */
4278 ts.push_back (entered_track);
4279 } else if (!selection->tracks.empty()) {
4280 /* Otherwise, if there are some selected tracks, paste to them */
4281 ts = selection->tracks.filter_to_unique_playlists ();
4282 sort_track_selection (ts);
4283 } else if (_last_cut_copy_source_track) {
4284 /* Otherwise paste to the track that the cut/copy came from;
4285 see discussion in mantis #3333.
4287 ts.push_back (_last_cut_copy_source_track);
4290 if (internal_editing ()) {
4292 /* undo/redo is handled by individual tracks/regions */
4294 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4297 RegionSelection::iterator r;
4298 MidiNoteSelection::iterator cb;
4300 get_regions_at (rs, position, ts);
4302 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4303 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4304 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4306 mrv->paste (position, times, **cb);
4314 /* we do redo (do you do voodoo?) */
4316 begin_reversible_command (Operations::paste);
4318 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4319 (*i)->paste (position, times, *cut_buffer, nth);
4322 commit_reversible_command ();
4327 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4329 boost::shared_ptr<Playlist> playlist;
4330 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4331 RegionSelection foo;
4333 framepos_t const start_frame = regions.start ();
4334 framepos_t const end_frame = regions.end_frame ();
4336 begin_reversible_command (Operations::duplicate_region);
4338 selection->clear_regions ();
4340 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4342 boost::shared_ptr<Region> r ((*i)->region());
4344 TimeAxisView& tv = (*i)->get_time_axis_view();
4345 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4346 latest_regionviews.clear ();
4347 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4349 playlist = (*i)->region()->playlist();
4350 playlist->clear_changes ();
4351 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4352 _session->add_command(new StatefulDiffCommand (playlist));
4356 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4359 commit_reversible_command ();
4362 selection->set (foo);
4367 Editor::duplicate_selection (float times)
4369 if (selection->time.empty() || selection->tracks.empty()) {
4373 boost::shared_ptr<Playlist> playlist;
4374 vector<boost::shared_ptr<Region> > new_regions;
4375 vector<boost::shared_ptr<Region> >::iterator ri;
4377 create_region_from_selection (new_regions);
4379 if (new_regions.empty()) {
4383 begin_reversible_command (_("duplicate selection"));
4385 ri = new_regions.begin();
4387 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4389 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4390 if ((playlist = (*i)->playlist()) == 0) {
4393 playlist->clear_changes ();
4394 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4395 _session->add_command (new StatefulDiffCommand (playlist));
4398 if (ri == new_regions.end()) {
4403 commit_reversible_command ();
4406 /** Reset all selected points to the relevant default value */
4408 Editor::reset_point_selection ()
4410 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4411 ARDOUR::AutomationList::iterator j = (*i)->model ();
4412 (*j)->value = (*i)->line().the_list()->default_value ();
4417 Editor::center_playhead ()
4419 float const page = _visible_canvas_width * samples_per_pixel;
4420 center_screen_internal (playhead_cursor->current_frame (), page);
4424 Editor::center_edit_point ()
4426 float const page = _visible_canvas_width * samples_per_pixel;
4427 center_screen_internal (get_preferred_edit_position(), page);
4430 /** Caller must begin and commit a reversible command */
4432 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4434 playlist->clear_changes ();
4436 _session->add_command (new StatefulDiffCommand (playlist));
4440 Editor::nudge_track (bool use_edit, bool forwards)
4442 boost::shared_ptr<Playlist> playlist;
4443 framepos_t distance;
4444 framepos_t next_distance;
4448 start = get_preferred_edit_position();
4453 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4457 if (selection->tracks.empty()) {
4461 begin_reversible_command (_("nudge track"));
4463 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4465 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4467 if ((playlist = (*i)->playlist()) == 0) {
4471 playlist->clear_changes ();
4472 playlist->clear_owned_changes ();
4474 playlist->nudge_after (start, distance, forwards);
4476 vector<Command*> cmds;
4478 playlist->rdiff (cmds);
4479 _session->add_commands (cmds);
4481 _session->add_command (new StatefulDiffCommand (playlist));
4484 commit_reversible_command ();
4488 Editor::remove_last_capture ()
4490 vector<string> choices;
4497 if (Config->get_verify_remove_last_capture()) {
4498 prompt = _("Do you really want to destroy the last capture?"
4499 "\n(This is destructive and cannot be undone)");
4501 choices.push_back (_("No, do nothing."));
4502 choices.push_back (_("Yes, destroy it."));
4504 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4506 if (prompter.run () == 1) {
4507 _session->remove_last_capture ();
4508 _regions->redisplay ();
4512 _session->remove_last_capture();
4513 _regions->redisplay ();
4518 Editor::normalize_region ()
4524 RegionSelection rs = get_regions_from_selection_and_entered ();
4530 NormalizeDialog dialog (rs.size() > 1);
4532 if (dialog.run () == RESPONSE_CANCEL) {
4536 set_canvas_cursor (_cursors->wait);
4539 /* XXX: should really only count audio regions here */
4540 int const regions = rs.size ();
4542 /* Make a list of the selected audio regions' maximum amplitudes, and also
4543 obtain the maximum amplitude of them all.
4545 list<double> max_amps;
4547 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4548 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4550 dialog.descend (1.0 / regions);
4551 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4554 /* the user cancelled the operation */
4555 set_canvas_cursor (current_canvas_cursor);
4559 max_amps.push_back (a);
4560 max_amp = max (max_amp, a);
4565 begin_reversible_command (_("normalize"));
4567 list<double>::const_iterator a = max_amps.begin ();
4569 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4570 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4575 arv->region()->clear_changes ();
4577 double const amp = dialog.normalize_individually() ? *a : max_amp;
4579 arv->audio_region()->normalize (amp, dialog.target ());
4580 _session->add_command (new StatefulDiffCommand (arv->region()));
4585 commit_reversible_command ();
4586 set_canvas_cursor (current_canvas_cursor);
4591 Editor::reset_region_scale_amplitude ()
4597 RegionSelection rs = get_regions_from_selection_and_entered ();
4603 begin_reversible_command ("reset gain");
4605 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4606 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4609 arv->region()->clear_changes ();
4610 arv->audio_region()->set_scale_amplitude (1.0f);
4611 _session->add_command (new StatefulDiffCommand (arv->region()));
4614 commit_reversible_command ();
4618 Editor::adjust_region_gain (bool up)
4620 RegionSelection rs = get_regions_from_selection_and_entered ();
4622 if (!_session || rs.empty()) {
4626 begin_reversible_command ("adjust region gain");
4628 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4629 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4634 arv->region()->clear_changes ();
4636 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4644 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4645 _session->add_command (new StatefulDiffCommand (arv->region()));
4648 commit_reversible_command ();
4653 Editor::reverse_region ()
4659 Reverse rev (*_session);
4660 apply_filter (rev, _("reverse regions"));
4664 Editor::strip_region_silence ()
4670 RegionSelection rs = get_regions_from_selection_and_entered ();
4676 std::list<RegionView*> audio_only;
4678 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4679 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4681 audio_only.push_back (arv);
4685 StripSilenceDialog d (_session, audio_only);
4686 int const r = d.run ();
4690 if (r == Gtk::RESPONSE_OK) {
4691 ARDOUR::AudioIntervalMap silences;
4692 d.silences (silences);
4693 StripSilence s (*_session, silences, d.fade_length());
4694 apply_filter (s, _("strip silence"), &d);
4699 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4701 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4702 mrv.selection_as_notelist (selected, true);
4704 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4705 v.push_back (selected);
4707 framepos_t pos_frames = mrv.midi_region()->position();
4708 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4710 return op (mrv.midi_region()->model(), pos_beats, v);
4714 Editor::apply_midi_note_edit_op (MidiOperator& op)
4718 RegionSelection rs = get_regions_from_selection_and_entered ();
4724 begin_reversible_command (op.name ());
4726 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4727 RegionSelection::iterator tmp = r;
4730 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4733 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4736 _session->add_command (cmd);
4743 commit_reversible_command ();
4747 Editor::fork_region ()
4749 RegionSelection rs = get_regions_from_selection_and_entered ();
4755 begin_reversible_command (_("Fork Region(s)"));
4757 set_canvas_cursor (_cursors->wait);
4760 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4761 RegionSelection::iterator tmp = r;
4764 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4767 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4768 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4770 playlist->clear_changes ();
4771 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4772 _session->add_command(new StatefulDiffCommand (playlist));
4778 commit_reversible_command ();
4780 set_canvas_cursor (current_canvas_cursor);
4784 Editor::quantize_region ()
4786 int selected_midi_region_cnt = 0;
4792 RegionSelection rs = get_regions_from_selection_and_entered ();
4798 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4799 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4801 selected_midi_region_cnt++;
4805 if (selected_midi_region_cnt == 0) {
4809 QuantizeDialog* qd = new QuantizeDialog (*this);
4812 const int r = qd->run ();
4815 if (r == Gtk::RESPONSE_OK) {
4816 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4817 qd->start_grid_size(), qd->end_grid_size(),
4818 qd->strength(), qd->swing(), qd->threshold());
4820 apply_midi_note_edit_op (quant);
4825 Editor::insert_patch_change (bool from_context)
4827 RegionSelection rs = get_regions_from_selection_and_entered ();
4833 const framepos_t p = get_preferred_edit_position (false, from_context);
4835 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4836 there may be more than one, but the PatchChangeDialog can only offer
4837 one set of patch menus.
4839 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4841 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4842 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4844 if (d.run() == RESPONSE_CANCEL) {
4848 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4849 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4851 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4852 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4859 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4861 RegionSelection rs = get_regions_from_selection_and_entered ();
4867 begin_reversible_command (command);
4869 set_canvas_cursor (_cursors->wait);
4873 int const N = rs.size ();
4875 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4876 RegionSelection::iterator tmp = r;
4879 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4881 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4884 progress->descend (1.0 / N);
4887 if (arv->audio_region()->apply (filter, progress) == 0) {
4889 playlist->clear_changes ();
4890 playlist->clear_owned_changes ();
4892 if (filter.results.empty ()) {
4894 /* no regions returned; remove the old one */
4895 playlist->remove_region (arv->region ());
4899 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4901 /* first region replaces the old one */
4902 playlist->replace_region (arv->region(), *res, (*res)->position());
4906 while (res != filter.results.end()) {
4907 playlist->add_region (*res, (*res)->position());
4913 /* We might have removed regions, which alters other regions' layering_index,
4914 so we need to do a recursive diff here.
4916 vector<Command*> cmds;
4917 playlist->rdiff (cmds);
4918 _session->add_commands (cmds);
4920 _session->add_command(new StatefulDiffCommand (playlist));
4926 progress->ascend ();
4934 commit_reversible_command ();
4937 set_canvas_cursor (current_canvas_cursor);
4941 Editor::external_edit_region ()
4947 Editor::reset_region_gain_envelopes ()
4949 RegionSelection rs = get_regions_from_selection_and_entered ();
4951 if (!_session || rs.empty()) {
4955 _session->begin_reversible_command (_("reset region gain"));
4957 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4958 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4960 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4961 XMLNode& before (alist->get_state());
4963 arv->audio_region()->set_default_envelope ();
4964 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4968 _session->commit_reversible_command ();
4972 Editor::set_region_gain_visibility (RegionView* rv)
4974 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4976 arv->update_envelope_visibility();
4981 Editor::set_gain_envelope_visibility ()
4987 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4988 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4990 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
4996 Editor::toggle_gain_envelope_active ()
4998 if (_ignore_region_action) {
5002 RegionSelection rs = get_regions_from_selection_and_entered ();
5004 if (!_session || rs.empty()) {
5008 _session->begin_reversible_command (_("region gain envelope active"));
5010 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5011 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5013 arv->region()->clear_changes ();
5014 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5015 _session->add_command (new StatefulDiffCommand (arv->region()));
5019 _session->commit_reversible_command ();
5023 Editor::toggle_region_lock ()
5025 if (_ignore_region_action) {
5029 RegionSelection rs = get_regions_from_selection_and_entered ();
5031 if (!_session || rs.empty()) {
5035 _session->begin_reversible_command (_("toggle region lock"));
5037 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5038 (*i)->region()->clear_changes ();
5039 (*i)->region()->set_locked (!(*i)->region()->locked());
5040 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5043 _session->commit_reversible_command ();
5047 Editor::toggle_region_video_lock ()
5049 if (_ignore_region_action) {
5053 RegionSelection rs = get_regions_from_selection_and_entered ();
5055 if (!_session || rs.empty()) {
5059 _session->begin_reversible_command (_("Toggle Video Lock"));
5061 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5062 (*i)->region()->clear_changes ();
5063 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5064 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5067 _session->commit_reversible_command ();
5071 Editor::toggle_region_lock_style ()
5073 if (_ignore_region_action) {
5077 RegionSelection rs = get_regions_from_selection_and_entered ();
5079 if (!_session || rs.empty()) {
5083 _session->begin_reversible_command (_("region lock style"));
5085 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5086 (*i)->region()->clear_changes ();
5087 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5088 (*i)->region()->set_position_lock_style (ns);
5089 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5092 _session->commit_reversible_command ();
5096 Editor::toggle_opaque_region ()
5098 if (_ignore_region_action) {
5102 RegionSelection rs = get_regions_from_selection_and_entered ();
5104 if (!_session || rs.empty()) {
5108 _session->begin_reversible_command (_("change region opacity"));
5110 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5111 (*i)->region()->clear_changes ();
5112 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5113 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5116 _session->commit_reversible_command ();
5120 Editor::toggle_record_enable ()
5122 bool new_state = false;
5124 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5125 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5128 if (!rtav->is_track())
5132 new_state = !rtav->track()->record_enabled();
5136 rtav->track()->set_record_enabled (new_state, this);
5141 Editor::toggle_solo ()
5143 bool new_state = false;
5145 boost::shared_ptr<RouteList> rl (new RouteList);
5147 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5148 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5155 new_state = !rtav->route()->soloed ();
5159 rl->push_back (rtav->route());
5162 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5166 Editor::toggle_mute ()
5168 bool new_state = false;
5170 boost::shared_ptr<RouteList> rl (new RouteList);
5172 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5173 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5180 new_state = !rtav->route()->muted();
5184 rl->push_back (rtav->route());
5187 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5191 Editor::toggle_solo_isolate ()
5196 Editor::set_fade_length (bool in)
5198 RegionSelection rs = get_regions_from_selection_and_entered ();
5204 /* we need a region to measure the offset from the start */
5206 RegionView* rv = rs.front ();
5208 framepos_t pos = get_preferred_edit_position();
5212 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5213 /* edit point is outside the relevant region */
5218 if (pos <= rv->region()->position()) {
5222 len = pos - rv->region()->position();
5223 cmd = _("set fade in length");
5225 if (pos >= rv->region()->last_frame()) {
5229 len = rv->region()->last_frame() - pos;
5230 cmd = _("set fade out length");
5233 begin_reversible_command (cmd);
5235 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5236 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5242 boost::shared_ptr<AutomationList> alist;
5244 alist = tmp->audio_region()->fade_in();
5246 alist = tmp->audio_region()->fade_out();
5249 XMLNode &before = alist->get_state();
5252 tmp->audio_region()->set_fade_in_length (len);
5253 tmp->audio_region()->set_fade_in_active (true);
5255 tmp->audio_region()->set_fade_out_length (len);
5256 tmp->audio_region()->set_fade_out_active (true);
5259 XMLNode &after = alist->get_state();
5260 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5263 commit_reversible_command ();
5267 Editor::set_fade_in_shape (FadeShape shape)
5269 RegionSelection rs = get_regions_from_selection_and_entered ();
5275 begin_reversible_command (_("set fade in shape"));
5277 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5278 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5284 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5285 XMLNode &before = alist->get_state();
5287 tmp->audio_region()->set_fade_in_shape (shape);
5289 XMLNode &after = alist->get_state();
5290 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5293 commit_reversible_command ();
5298 Editor::set_fade_out_shape (FadeShape shape)
5300 RegionSelection rs = get_regions_from_selection_and_entered ();
5306 begin_reversible_command (_("set fade out shape"));
5308 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5309 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5315 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5316 XMLNode &before = alist->get_state();
5318 tmp->audio_region()->set_fade_out_shape (shape);
5320 XMLNode &after = alist->get_state();
5321 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5324 commit_reversible_command ();
5328 Editor::set_fade_in_active (bool yn)
5330 RegionSelection rs = get_regions_from_selection_and_entered ();
5336 begin_reversible_command (_("set fade in active"));
5338 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5339 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5346 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5348 ar->clear_changes ();
5349 ar->set_fade_in_active (yn);
5350 _session->add_command (new StatefulDiffCommand (ar));
5353 commit_reversible_command ();
5357 Editor::set_fade_out_active (bool yn)
5359 RegionSelection rs = get_regions_from_selection_and_entered ();
5365 begin_reversible_command (_("set fade out active"));
5367 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5368 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5374 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5376 ar->clear_changes ();
5377 ar->set_fade_out_active (yn);
5378 _session->add_command(new StatefulDiffCommand (ar));
5381 commit_reversible_command ();
5385 Editor::toggle_region_fades (int dir)
5387 if (_ignore_region_action) {
5391 boost::shared_ptr<AudioRegion> ar;
5394 RegionSelection rs = get_regions_from_selection_and_entered ();
5400 RegionSelection::iterator i;
5401 for (i = rs.begin(); i != rs.end(); ++i) {
5402 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5404 yn = ar->fade_out_active ();
5406 yn = ar->fade_in_active ();
5412 if (i == rs.end()) {
5416 /* XXX should this undo-able? */
5418 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5419 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5422 if (dir == 1 || dir == 0) {
5423 ar->set_fade_in_active (!yn);
5426 if (dir == -1 || dir == 0) {
5427 ar->set_fade_out_active (!yn);
5433 /** Update region fade visibility after its configuration has been changed */
5435 Editor::update_region_fade_visibility ()
5437 bool _fade_visibility = _session->config.get_show_region_fades ();
5439 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5440 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5442 if (_fade_visibility) {
5443 v->audio_view()->show_all_fades ();
5445 v->audio_view()->hide_all_fades ();
5452 Editor::set_edit_point ()
5457 if (!mouse_frame (where, ignored)) {
5463 if (selection->markers.empty()) {
5465 mouse_add_new_marker (where);
5470 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5473 loc->move_to (where);
5479 Editor::set_playhead_cursor ()
5481 if (entered_marker) {
5482 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5487 if (!mouse_frame (where, ignored)) {
5494 _session->request_locate (where, _session->transport_rolling());
5498 if ( Config->get_always_play_range() )
5499 cancel_time_selection();
5503 Editor::split_region ()
5505 if ( !selection->time.empty()) {
5506 separate_regions_between (selection->time);
5510 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5512 framepos_t where = get_preferred_edit_position ();
5518 split_regions_at (where, rs);
5521 struct EditorOrderRouteSorter {
5522 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5523 return a->order_key (EditorSort) < b->order_key (EditorSort);
5528 Editor::select_next_route()
5530 if (selection->tracks.empty()) {
5531 selection->set (track_views.front());
5535 TimeAxisView* current = selection->tracks.front();
5539 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5540 if (*i == current) {
5542 if (i != track_views.end()) {
5545 current = (*(track_views.begin()));
5546 //selection->set (*(track_views.begin()));
5551 rui = dynamic_cast<RouteUI *>(current);
5552 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5554 selection->set(current);
5556 ensure_track_visible(current);
5560 Editor::select_prev_route()
5562 if (selection->tracks.empty()) {
5563 selection->set (track_views.front());
5567 TimeAxisView* current = selection->tracks.front();
5571 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5572 if (*i == current) {
5574 if (i != track_views.rend()) {
5577 current = *(track_views.rbegin());
5582 rui = dynamic_cast<RouteUI *>(current);
5583 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5585 selection->set (current);
5587 ensure_track_visible(current);
5591 Editor::ensure_track_visible(TimeAxisView *track)
5593 if (track->hidden())
5596 double const current_view_min_y = vertical_adjustment.get_value();
5597 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5599 double const track_min_y = track->y_position ();
5600 double const track_max_y = track->y_position () + track->effective_height ();
5602 if (track_min_y >= current_view_min_y &&
5603 track_max_y <= current_view_max_y) {
5609 if (track_min_y < current_view_min_y) {
5610 // Track is above the current view
5611 new_value = track_min_y;
5613 // Track is below the current view
5614 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5617 vertical_adjustment.set_value(new_value);
5621 Editor::set_loop_from_selection (bool play)
5623 if (_session == 0 || selection->time.empty()) {
5627 framepos_t start = selection->time[clicked_selection].start;
5628 framepos_t end = selection->time[clicked_selection].end;
5630 set_loop_range (start, end, _("set loop range from selection"));
5633 _session->request_play_loop (true);
5634 _session->request_locate (start, true);
5639 Editor::set_loop_from_edit_range (bool play)
5641 if (_session == 0) {
5648 if (!get_edit_op_range (start, end)) {
5652 set_loop_range (start, end, _("set loop range from edit range"));
5655 _session->request_play_loop (true);
5656 _session->request_locate (start, true);
5661 Editor::set_loop_from_region (bool play)
5663 framepos_t start = max_framepos;
5666 RegionSelection rs = get_regions_from_selection_and_entered ();
5672 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5673 if ((*i)->region()->position() < start) {
5674 start = (*i)->region()->position();
5676 if ((*i)->region()->last_frame() + 1 > end) {
5677 end = (*i)->region()->last_frame() + 1;
5681 set_loop_range (start, end, _("set loop range from region"));
5684 _session->request_play_loop (true);
5685 _session->request_locate (start, true);
5690 Editor::set_punch_from_selection ()
5692 if (_session == 0 || selection->time.empty()) {
5696 framepos_t start = selection->time[clicked_selection].start;
5697 framepos_t end = selection->time[clicked_selection].end;
5699 set_punch_range (start, end, _("set punch range from selection"));
5703 Editor::set_punch_from_edit_range ()
5705 if (_session == 0) {
5712 if (!get_edit_op_range (start, end)) {
5716 set_punch_range (start, end, _("set punch range from edit range"));
5720 Editor::set_punch_from_region ()
5722 framepos_t start = max_framepos;
5725 RegionSelection rs = get_regions_from_selection_and_entered ();
5731 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5732 if ((*i)->region()->position() < start) {
5733 start = (*i)->region()->position();
5735 if ((*i)->region()->last_frame() + 1 > end) {
5736 end = (*i)->region()->last_frame() + 1;
5740 set_punch_range (start, end, _("set punch range from region"));
5744 Editor::pitch_shift_region ()
5746 RegionSelection rs = get_regions_from_selection_and_entered ();
5748 RegionSelection audio_rs;
5749 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5750 if (dynamic_cast<AudioRegionView*> (*i)) {
5751 audio_rs.push_back (*i);
5755 if (audio_rs.empty()) {
5759 pitch_shift (audio_rs, 1.2);
5763 Editor::transpose_region ()
5765 RegionSelection rs = get_regions_from_selection_and_entered ();
5767 list<MidiRegionView*> midi_region_views;
5768 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5769 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5771 midi_region_views.push_back (mrv);
5776 int const r = d.run ();
5777 if (r != RESPONSE_ACCEPT) {
5781 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5782 (*i)->midi_region()->transpose (d.semitones ());
5787 Editor::set_tempo_from_region ()
5789 RegionSelection rs = get_regions_from_selection_and_entered ();
5791 if (!_session || rs.empty()) {
5795 RegionView* rv = rs.front();
5797 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5801 Editor::use_range_as_bar ()
5803 framepos_t start, end;
5804 if (get_edit_op_range (start, end)) {
5805 define_one_bar (start, end);
5810 Editor::define_one_bar (framepos_t start, framepos_t end)
5812 framepos_t length = end - start;
5814 const Meter& m (_session->tempo_map().meter_at (start));
5816 /* length = 1 bar */
5818 /* now we want frames per beat.
5819 we have frames per bar, and beats per bar, so ...
5822 /* XXXX METER MATH */
5824 double frames_per_beat = length / m.divisions_per_bar();
5826 /* beats per minute = */
5828 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5830 /* now decide whether to:
5832 (a) set global tempo
5833 (b) add a new tempo marker
5837 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5839 bool do_global = false;
5841 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5843 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5844 at the start, or create a new marker
5847 vector<string> options;
5848 options.push_back (_("Cancel"));
5849 options.push_back (_("Add new marker"));
5850 options.push_back (_("Set global tempo"));
5853 _("Define one bar"),
5854 _("Do you want to set the global tempo or add a new tempo marker?"),
5858 c.set_default_response (2);
5874 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5875 if the marker is at the region starter, change it, otherwise add
5880 begin_reversible_command (_("set tempo from region"));
5881 XMLNode& before (_session->tempo_map().get_state());
5884 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5885 } else if (t.frame() == start) {
5886 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5888 Timecode::BBT_Time bbt;
5889 _session->tempo_map().bbt_time (start, bbt);
5890 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5893 XMLNode& after (_session->tempo_map().get_state());
5895 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5896 commit_reversible_command ();
5900 Editor::split_region_at_transients ()
5902 AnalysisFeatureList positions;
5904 RegionSelection rs = get_regions_from_selection_and_entered ();
5906 if (!_session || rs.empty()) {
5910 _session->begin_reversible_command (_("split regions"));
5912 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5914 RegionSelection::iterator tmp;
5919 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5921 if (ar && (ar->get_transients (positions) == 0)) {
5922 split_region_at_points ((*i)->region(), positions, true);
5929 _session->commit_reversible_command ();
5934 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5936 bool use_rhythmic_rodent = false;
5938 boost::shared_ptr<Playlist> pl = r->playlist();
5940 list<boost::shared_ptr<Region> > new_regions;
5946 if (positions.empty()) {
5951 if (positions.size() > 20 && can_ferret) {
5952 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);
5953 MessageDialog msg (msgstr,
5956 Gtk::BUTTONS_OK_CANCEL);
5959 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5960 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5962 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5965 msg.set_title (_("Excessive split?"));
5968 int response = msg.run();
5974 case RESPONSE_APPLY:
5975 use_rhythmic_rodent = true;
5982 if (use_rhythmic_rodent) {
5983 show_rhythm_ferret ();
5987 AnalysisFeatureList::const_iterator x;
5989 pl->clear_changes ();
5990 pl->clear_owned_changes ();
5992 x = positions.begin();
5994 if (x == positions.end()) {
5999 pl->remove_region (r);
6003 while (x != positions.end()) {
6005 /* deal with positons that are out of scope of present region bounds */
6006 if (*x <= 0 || *x > r->length()) {
6011 /* file start = original start + how far we from the initial position ?
6014 framepos_t file_start = r->start() + pos;
6016 /* length = next position - current position
6019 framepos_t len = (*x) - pos;
6021 /* XXX we do we really want to allow even single-sample regions?
6022 shouldn't we have some kind of lower limit on region size?
6031 if (RegionFactory::region_name (new_name, r->name())) {
6035 /* do NOT announce new regions 1 by one, just wait till they are all done */
6039 plist.add (ARDOUR::Properties::start, file_start);
6040 plist.add (ARDOUR::Properties::length, len);
6041 plist.add (ARDOUR::Properties::name, new_name);
6042 plist.add (ARDOUR::Properties::layer, 0);
6044 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6045 /* because we set annouce to false, manually add the new region to the
6048 RegionFactory::map_add (nr);
6050 pl->add_region (nr, r->position() + pos);
6053 new_regions.push_front(nr);
6062 RegionFactory::region_name (new_name, r->name());
6064 /* Add the final region */
6067 plist.add (ARDOUR::Properties::start, r->start() + pos);
6068 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6069 plist.add (ARDOUR::Properties::name, new_name);
6070 plist.add (ARDOUR::Properties::layer, 0);
6072 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6073 /* because we set annouce to false, manually add the new region to the
6076 RegionFactory::map_add (nr);
6077 pl->add_region (nr, r->position() + pos);
6080 new_regions.push_front(nr);
6085 /* We might have removed regions, which alters other regions' layering_index,
6086 so we need to do a recursive diff here.
6088 vector<Command*> cmds;
6090 _session->add_commands (cmds);
6092 _session->add_command (new StatefulDiffCommand (pl));
6096 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6097 set_selected_regionview_from_region_list ((*i), Selection::Add);
6103 Editor::place_transient()
6109 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6115 framepos_t where = get_preferred_edit_position();
6117 _session->begin_reversible_command (_("place transient"));
6119 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6120 framepos_t position = (*r)->region()->position();
6121 (*r)->region()->add_transient(where - position);
6124 _session->commit_reversible_command ();
6128 Editor::remove_transient(ArdourCanvas::Item* item)
6134 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6137 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6138 _arv->remove_transient (*(float*) _line->get_data ("position"));
6142 Editor::snap_regions_to_grid ()
6144 list <boost::shared_ptr<Playlist > > used_playlists;
6146 RegionSelection rs = get_regions_from_selection_and_entered ();
6148 if (!_session || rs.empty()) {
6152 _session->begin_reversible_command (_("snap regions to grid"));
6154 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6156 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6158 if (!pl->frozen()) {
6159 /* we haven't seen this playlist before */
6161 /* remember used playlists so we can thaw them later */
6162 used_playlists.push_back(pl);
6166 framepos_t start_frame = (*r)->region()->first_frame ();
6167 snap_to (start_frame);
6168 (*r)->region()->set_position (start_frame);
6171 while (used_playlists.size() > 0) {
6172 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6174 used_playlists.pop_front();
6177 _session->commit_reversible_command ();
6181 Editor::close_region_gaps ()
6183 list <boost::shared_ptr<Playlist > > used_playlists;
6185 RegionSelection rs = get_regions_from_selection_and_entered ();
6187 if (!_session || rs.empty()) {
6191 Dialog dialog (_("Close Region Gaps"));
6194 table.set_spacings (12);
6195 table.set_border_width (12);
6196 Label* l = manage (left_aligned_label (_("Crossfade length")));
6197 table.attach (*l, 0, 1, 0, 1);
6199 SpinButton spin_crossfade (1, 0);
6200 spin_crossfade.set_range (0, 15);
6201 spin_crossfade.set_increments (1, 1);
6202 spin_crossfade.set_value (5);
6203 table.attach (spin_crossfade, 1, 2, 0, 1);
6205 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6207 l = manage (left_aligned_label (_("Pull-back length")));
6208 table.attach (*l, 0, 1, 1, 2);
6210 SpinButton spin_pullback (1, 0);
6211 spin_pullback.set_range (0, 100);
6212 spin_pullback.set_increments (1, 1);
6213 spin_pullback.set_value(30);
6214 table.attach (spin_pullback, 1, 2, 1, 2);
6216 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6218 dialog.get_vbox()->pack_start (table);
6219 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6220 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6223 if (dialog.run () == RESPONSE_CANCEL) {
6227 framepos_t crossfade_len = spin_crossfade.get_value();
6228 framepos_t pull_back_frames = spin_pullback.get_value();
6230 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6231 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6233 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6235 _session->begin_reversible_command (_("close region gaps"));
6238 boost::shared_ptr<Region> last_region;
6240 rs.sort_by_position_and_track();
6242 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6244 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6246 if (!pl->frozen()) {
6247 /* we haven't seen this playlist before */
6249 /* remember used playlists so we can thaw them later */
6250 used_playlists.push_back(pl);
6254 framepos_t position = (*r)->region()->position();
6256 if (idx == 0 || position < last_region->position()){
6257 last_region = (*r)->region();
6262 (*r)->region()->trim_front( (position - pull_back_frames));
6263 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6265 last_region = (*r)->region();
6270 while (used_playlists.size() > 0) {
6271 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6273 used_playlists.pop_front();
6276 _session->commit_reversible_command ();
6280 Editor::tab_to_transient (bool forward)
6282 AnalysisFeatureList positions;
6284 RegionSelection rs = get_regions_from_selection_and_entered ();
6290 framepos_t pos = _session->audible_frame ();
6292 if (!selection->tracks.empty()) {
6294 /* don't waste time searching for transients in duplicate playlists.
6297 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6299 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6301 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6304 boost::shared_ptr<Track> tr = rtv->track();
6306 boost::shared_ptr<Playlist> pl = tr->playlist ();
6308 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6311 positions.push_back (result);
6324 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6325 (*r)->region()->get_transients (positions);
6329 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6332 AnalysisFeatureList::iterator x;
6334 for (x = positions.begin(); x != positions.end(); ++x) {
6340 if (x != positions.end ()) {
6341 _session->request_locate (*x);
6345 AnalysisFeatureList::reverse_iterator x;
6347 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6353 if (x != positions.rend ()) {
6354 _session->request_locate (*x);
6360 Editor::playhead_forward_to_grid ()
6366 framepos_t pos = playhead_cursor->current_frame ();
6367 if (pos < max_framepos - 1) {
6369 snap_to_internal (pos, 1, false);
6370 _session->request_locate (pos);
6376 Editor::playhead_backward_to_grid ()
6382 framepos_t pos = playhead_cursor->current_frame ();
6385 snap_to_internal (pos, -1, false);
6386 _session->request_locate (pos);
6391 Editor::set_track_height (Height h)
6393 TrackSelection& ts (selection->tracks);
6395 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6396 (*x)->set_height_enum (h);
6401 Editor::toggle_tracks_active ()
6403 TrackSelection& ts (selection->tracks);
6405 bool target = false;
6411 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6412 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6416 target = !rtv->_route->active();
6419 rtv->_route->set_active (target, this);
6425 Editor::remove_tracks ()
6427 TrackSelection& ts (selection->tracks);
6433 vector<string> choices;
6437 const char* trackstr;
6439 vector<boost::shared_ptr<Route> > routes;
6440 bool special_bus = false;
6442 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6443 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6445 if (rtv->is_track()) {
6451 routes.push_back (rtv->_route);
6453 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6458 if (special_bus && !Config->get_allow_special_bus_removal()) {
6459 MessageDialog msg (_("That would be bad news ...."),
6463 msg.set_secondary_text (string_compose (_(
6464 "Removing the master or monitor bus is such a bad idea\n\
6465 that %1 is not going to allow it.\n\
6467 If you really want to do this sort of thing\n\
6468 edit your ardour.rc file to set the\n\
6469 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6476 if (ntracks + nbusses == 0) {
6481 trackstr = _("tracks");
6483 trackstr = _("track");
6487 busstr = _("busses");
6494 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6495 "(You may also lose the playlists associated with the %2)\n\n"
6496 "This action cannot be undone, and the session file will be overwritten!"),
6497 ntracks, trackstr, nbusses, busstr);
6499 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6500 "(You may also lose the playlists associated with the %2)\n\n"
6501 "This action cannot be undone, and the session file will be overwritten!"),
6504 } else if (nbusses) {
6505 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6506 "This action cannot be undon, and the session file will be overwritten"),
6510 choices.push_back (_("No, do nothing."));
6511 if (ntracks + nbusses > 1) {
6512 choices.push_back (_("Yes, remove them."));
6514 choices.push_back (_("Yes, remove it."));
6519 title = string_compose (_("Remove %1"), trackstr);
6521 title = string_compose (_("Remove %1"), busstr);
6524 Choice prompter (title, prompt, choices);
6526 if (prompter.run () != 1) {
6530 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6531 _session->remove_route (*x);
6536 Editor::do_insert_time ()
6538 if (selection->tracks.empty()) {
6542 InsertTimeDialog d (*this);
6543 int response = d.run ();
6545 if (response != RESPONSE_OK) {
6549 if (d.distance() == 0) {
6553 InsertTimeOption opt = d.intersected_region_action ();
6556 get_preferred_edit_position(),
6562 d.move_glued_markers(),
6563 d.move_locked_markers(),
6569 Editor::insert_time (
6570 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6571 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6574 bool commit = false;
6576 if (Config->get_edit_mode() == Lock) {
6580 begin_reversible_command (_("insert time"));
6582 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6584 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6588 /* don't operate on any playlist more than once, which could
6589 * happen if "all playlists" is enabled, but there is more
6590 * than 1 track using playlists "from" a given track.
6593 set<boost::shared_ptr<Playlist> > pl;
6595 if (all_playlists) {
6596 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6598 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6599 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6604 if ((*x)->playlist ()) {
6605 pl.insert ((*x)->playlist ());
6609 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6611 (*i)->clear_changes ();
6612 (*i)->clear_owned_changes ();
6614 if (opt == SplitIntersected) {
6618 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6620 vector<Command*> cmds;
6622 _session->add_commands (cmds);
6624 _session->add_command (new StatefulDiffCommand (*i));
6629 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6631 rtav->route ()->shift (pos, frames);
6639 XMLNode& before (_session->locations()->get_state());
6640 Locations::LocationList copy (_session->locations()->list());
6642 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6644 Locations::LocationList::const_iterator tmp;
6646 bool const was_locked = (*i)->locked ();
6647 if (locked_markers_too) {
6651 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6653 if ((*i)->start() >= pos) {
6654 (*i)->set_start ((*i)->start() + frames);
6655 if (!(*i)->is_mark()) {
6656 (*i)->set_end ((*i)->end() + frames);
6669 XMLNode& after (_session->locations()->get_state());
6670 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6675 _session->tempo_map().insert_time (pos, frames);
6679 commit_reversible_command ();
6684 Editor::fit_selected_tracks ()
6686 if (!selection->tracks.empty()) {
6687 fit_tracks (selection->tracks);
6691 /* no selected tracks - use tracks with selected regions */
6693 if (!selection->regions.empty()) {
6694 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6695 tvl.push_back (&(*r)->get_time_axis_view ());
6701 } else if (internal_editing()) {
6702 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6705 if (entered_track) {
6706 tvl.push_back (entered_track);
6714 Editor::fit_tracks (TrackViewList & tracks)
6716 if (tracks.empty()) {
6720 uint32_t child_heights = 0;
6721 int visible_tracks = 0;
6723 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6725 if (!(*t)->marked_for_display()) {
6729 child_heights += (*t)->effective_height() - (*t)->current_height();
6733 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6734 double first_y_pos = DBL_MAX;
6736 if (h < TimeAxisView::preset_height (HeightSmall)) {
6737 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6738 /* too small to be displayed */
6742 undo_visual_stack.push_back (current_visual_state (true));
6743 no_save_visual = true;
6745 /* build a list of all tracks, including children */
6748 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6750 TimeAxisView::Children c = (*i)->get_child_list ();
6751 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6752 all.push_back (j->get());
6756 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6758 bool prev_was_selected = false;
6759 bool is_selected = tracks.contains (all.front());
6760 bool next_is_selected;
6762 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6764 TrackViewList::iterator next;
6769 if (next != all.end()) {
6770 next_is_selected = tracks.contains (*next);
6772 next_is_selected = false;
6775 if ((*t)->marked_for_display ()) {
6777 (*t)->set_height (h);
6778 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6780 if (prev_was_selected && next_is_selected) {
6781 hide_track_in_display (*t);
6786 prev_was_selected = is_selected;
6787 is_selected = next_is_selected;
6791 set the controls_layout height now, because waiting for its size
6792 request signal handler will cause the vertical adjustment setting to fail
6795 controls_layout.property_height () = _full_canvas_height;
6796 vertical_adjustment.set_value (first_y_pos);
6798 redo_visual_stack.push_back (current_visual_state (true));
6802 Editor::save_visual_state (uint32_t n)
6804 while (visual_states.size() <= n) {
6805 visual_states.push_back (0);
6808 if (visual_states[n] != 0) {
6809 delete visual_states[n];
6812 visual_states[n] = current_visual_state (true);
6817 Editor::goto_visual_state (uint32_t n)
6819 if (visual_states.size() <= n) {
6823 if (visual_states[n] == 0) {
6827 use_visual_state (*visual_states[n]);
6831 Editor::start_visual_state_op (uint32_t n)
6833 save_visual_state (n);
6835 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6837 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6838 pup->set_text (buf);
6843 Editor::cancel_visual_state_op (uint32_t n)
6845 goto_visual_state (n);
6849 Editor::toggle_region_mute ()
6851 if (_ignore_region_action) {
6855 RegionSelection rs = get_regions_from_selection_and_entered ();
6861 if (rs.size() > 1) {
6862 begin_reversible_command (_("mute regions"));
6864 begin_reversible_command (_("mute region"));
6867 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6869 (*i)->region()->playlist()->clear_changes ();
6870 (*i)->region()->set_muted (!(*i)->region()->muted ());
6871 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6875 commit_reversible_command ();
6879 Editor::combine_regions ()
6881 /* foreach track with selected regions, take all selected regions
6882 and join them into a new region containing the subregions (as a
6886 typedef set<RouteTimeAxisView*> RTVS;
6889 if (selection->regions.empty()) {
6893 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6894 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6897 tracks.insert (rtv);
6901 begin_reversible_command (_("combine regions"));
6903 vector<RegionView*> new_selection;
6905 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6908 if ((rv = (*i)->combine_regions ()) != 0) {
6909 new_selection.push_back (rv);
6913 selection->clear_regions ();
6914 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6915 selection->add (*i);
6918 commit_reversible_command ();
6922 Editor::uncombine_regions ()
6924 typedef set<RouteTimeAxisView*> RTVS;
6927 if (selection->regions.empty()) {
6931 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6932 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6935 tracks.insert (rtv);
6939 begin_reversible_command (_("uncombine regions"));
6941 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6942 (*i)->uncombine_regions ();
6945 commit_reversible_command ();
6949 Editor::toggle_midi_input_active (bool flip_others)
6952 boost::shared_ptr<RouteList> rl (new RouteList);
6954 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6955 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6961 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6964 rl->push_back (rtav->route());
6965 onoff = !mt->input_active();
6969 _session->set_exclusive_input_active (rl, onoff, flip_others);