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_frames() / 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 * frames_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 * frames_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_frames_per_pixel (double& fpp) const
1336 bool clamped = false;
1343 if (max_framepos / fpp < 800) {
1344 fpp = max_framepos / 800.0;
1352 Editor::temporal_zoom_step (bool coarser)
1354 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1356 double nfpp = frames_per_pixel;
1359 nfpp = min (9e6, nfpp * 1.61803399);
1361 nfpp = max (1.0, nfpp / 1.61803399);
1364 temporal_zoom (nfpp);
1368 Editor::temporal_zoom (double fpp)
1374 framepos_t current_page = current_page_frames();
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_frames_per_pixel (fpp);
1387 if (fpp == frames_per_pixel) {
1393 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1394 // segfaults for lack of memory. If somebody decides this is not high enough I
1395 // believe it can be raisen to higher values but some limit must be in place.
1400 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1401 half_page_size = new_page_size / 2;
1403 switch (zoom_focus) {
1405 leftmost_after_zoom = current_leftmost;
1408 case ZoomFocusRight:
1409 current_rightmost = leftmost_frame + current_page;
1410 if (current_rightmost < new_page_size) {
1411 leftmost_after_zoom = 0;
1413 leftmost_after_zoom = current_rightmost - new_page_size;
1417 case ZoomFocusCenter:
1418 current_center = current_leftmost + (current_page/2);
1419 if (current_center < half_page_size) {
1420 leftmost_after_zoom = 0;
1422 leftmost_after_zoom = current_center - half_page_size;
1426 case ZoomFocusPlayhead:
1427 /* centre playhead */
1428 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1431 leftmost_after_zoom = 0;
1432 } else if (l > max_framepos) {
1433 leftmost_after_zoom = max_framepos - new_page_size;
1435 leftmost_after_zoom = (framepos_t) l;
1439 case ZoomFocusMouse:
1440 /* try to keep the mouse over the same point in the display */
1442 if (!mouse_frame (where, in_track_canvas)) {
1443 /* use playhead instead */
1444 where = playhead_cursor->current_frame ();
1446 if (where < half_page_size) {
1447 leftmost_after_zoom = 0;
1449 leftmost_after_zoom = where - half_page_size;
1454 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1457 leftmost_after_zoom = 0;
1458 } else if (l > max_framepos) {
1459 leftmost_after_zoom = max_framepos - new_page_size;
1461 leftmost_after_zoom = (framepos_t) l;
1468 /* try to keep the edit point in the same place */
1469 where = get_preferred_edit_position ();
1473 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1476 leftmost_after_zoom = 0;
1477 } else if (l > max_framepos) {
1478 leftmost_after_zoom = max_framepos - new_page_size;
1480 leftmost_after_zoom = (framepos_t) l;
1484 /* edit point not defined */
1491 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1493 reposition_and_zoom (leftmost_after_zoom, nfpp);
1497 Editor::temporal_zoom_region (bool both_axes)
1499 framepos_t start = max_framepos;
1501 set<TimeAxisView*> tracks;
1503 RegionSelection rs = get_regions_from_selection_and_entered ();
1509 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1511 if ((*i)->region()->position() < start) {
1512 start = (*i)->region()->position();
1515 if ((*i)->region()->last_frame() + 1 > end) {
1516 end = (*i)->region()->last_frame() + 1;
1519 tracks.insert (&((*i)->get_time_axis_view()));
1522 /* now comes an "interesting" hack ... make sure we leave a little space
1523 at each end of the editor so that the zoom doesn't fit the region
1524 precisely to the screen.
1527 GdkScreen* screen = gdk_screen_get_default ();
1528 gint pixwidth = gdk_screen_get_width (screen);
1529 gint mmwidth = gdk_screen_get_width_mm (screen);
1530 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1531 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1533 if ((start == 0 && end == 0) || end < start) {
1537 framepos_t range = end - start;
1538 double new_fpp = (double) range / (double) _visible_canvas_width;
1539 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1541 if (start > extra_samples) {
1542 start -= extra_samples;
1547 if (max_framepos - extra_samples > end) {
1548 end += extra_samples;
1553 /* if we're zooming on both axes we need to save track heights etc.
1556 undo_visual_stack.push_back (current_visual_state (both_axes));
1558 PBD::Unwinder<bool> nsv (no_save_visual, true);
1560 temporal_zoom_by_frame (start, end);
1563 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1565 /* set visible track heights appropriately */
1567 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1568 (*t)->set_height (per_track_height);
1571 /* hide irrelevant tracks */
1573 _routes->suspend_redisplay ();
1575 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1576 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1577 hide_track_in_display (*i);
1581 _routes->resume_redisplay ();
1583 vertical_adjustment.set_value (0.0);
1586 redo_visual_stack.push_back (current_visual_state (both_axes));
1590 Editor::zoom_to_region (bool both_axes)
1592 temporal_zoom_region (both_axes);
1596 Editor::temporal_zoom_selection ()
1598 if (!selection) return;
1600 if (selection->time.empty()) {
1604 framepos_t start = selection->time[clicked_selection].start;
1605 framepos_t end = selection->time[clicked_selection].end;
1607 temporal_zoom_by_frame (start, end);
1611 Editor::temporal_zoom_session ()
1613 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1616 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1617 double s = _session->current_start_frame() - l * 0.01;
1621 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1622 temporal_zoom_by_frame (framecnt_t (s), e);
1627 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1629 if (!_session) return;
1631 if ((start == 0 && end == 0) || end < start) {
1635 framepos_t range = end - start;
1637 double const new_fpp = (double) range / (double) _visible_canvas_width;
1639 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1640 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1641 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1643 if (new_leftmost > middle) {
1647 if (new_leftmost < 0) {
1651 reposition_and_zoom (new_leftmost, new_fpp);
1655 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1660 double range_before = frame - leftmost_frame;
1663 new_fpp = frames_per_pixel;
1666 new_fpp *= 1.61803399;
1667 range_before *= 1.61803399;
1669 new_fpp = max(1.0,(new_fpp/1.61803399));
1670 range_before /= 1.61803399;
1673 if (new_fpp == frames_per_pixel) {
1677 framepos_t new_leftmost = frame - (framepos_t)range_before;
1679 if (new_leftmost > frame) {
1683 if (new_leftmost < 0) {
1687 reposition_and_zoom (new_leftmost, new_fpp);
1692 Editor::choose_new_marker_name(string &name) {
1694 if (!Config->get_name_new_markers()) {
1695 /* don't prompt user for a new name */
1699 ArdourPrompter dialog (true);
1701 dialog.set_prompt (_("New Name:"));
1703 dialog.set_title (_("New Location Marker"));
1705 dialog.set_name ("MarkNameWindow");
1706 dialog.set_size_request (250, -1);
1707 dialog.set_position (Gtk::WIN_POS_MOUSE);
1709 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1710 dialog.set_initial_text (name);
1714 switch (dialog.run ()) {
1715 case RESPONSE_ACCEPT:
1721 dialog.get_result(name);
1728 Editor::add_location_from_selection ()
1732 if (selection->time.empty()) {
1736 if (_session == 0 || clicked_axisview == 0) {
1740 framepos_t start = selection->time[clicked_selection].start;
1741 framepos_t end = selection->time[clicked_selection].end;
1743 _session->locations()->next_available_name(rangename,"selection");
1744 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1746 _session->begin_reversible_command (_("add marker"));
1747 XMLNode &before = _session->locations()->get_state();
1748 _session->locations()->add (location, true);
1749 XMLNode &after = _session->locations()->get_state();
1750 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1751 _session->commit_reversible_command ();
1755 Editor::add_location_mark (framepos_t where)
1759 select_new_marker = true;
1761 _session->locations()->next_available_name(markername,"mark");
1762 if (!choose_new_marker_name(markername)) {
1765 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1766 _session->begin_reversible_command (_("add marker"));
1767 XMLNode &before = _session->locations()->get_state();
1768 _session->locations()->add (location, true);
1769 XMLNode &after = _session->locations()->get_state();
1770 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1771 _session->commit_reversible_command ();
1775 Editor::add_location_from_playhead_cursor ()
1777 add_location_mark (_session->audible_frame());
1780 /** Add a range marker around each selected region */
1782 Editor::add_locations_from_region ()
1784 RegionSelection rs = get_regions_from_selection_and_entered ();
1790 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1791 XMLNode &before = _session->locations()->get_state();
1793 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1795 boost::shared_ptr<Region> region = (*i)->region ();
1797 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1799 _session->locations()->add (location, true);
1802 XMLNode &after = _session->locations()->get_state();
1803 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1804 _session->commit_reversible_command ();
1807 /** Add a single range marker around all selected regions */
1809 Editor::add_location_from_region ()
1811 RegionSelection rs = get_regions_from_selection_and_entered ();
1817 _session->begin_reversible_command (_("add marker"));
1818 XMLNode &before = _session->locations()->get_state();
1822 if (rs.size() > 1) {
1823 _session->locations()->next_available_name(markername, "regions");
1825 RegionView* rv = *(rs.begin());
1826 boost::shared_ptr<Region> region = rv->region();
1827 markername = region->name();
1830 if (!choose_new_marker_name(markername)) {
1834 // single range spanning all selected
1835 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1836 _session->locations()->add (location, true);
1838 XMLNode &after = _session->locations()->get_state();
1839 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1840 _session->commit_reversible_command ();
1846 Editor::jump_forward_to_mark ()
1852 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
1858 _session->request_locate (pos, _session->transport_rolling());
1862 Editor::jump_backward_to_mark ()
1868 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
1874 _session->request_locate (pos, _session->transport_rolling());
1880 framepos_t const pos = _session->audible_frame ();
1883 _session->locations()->next_available_name (markername, "mark");
1885 if (!choose_new_marker_name (markername)) {
1889 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1893 Editor::clear_markers ()
1896 _session->begin_reversible_command (_("clear markers"));
1897 XMLNode &before = _session->locations()->get_state();
1898 _session->locations()->clear_markers ();
1899 XMLNode &after = _session->locations()->get_state();
1900 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1901 _session->commit_reversible_command ();
1906 Editor::clear_ranges ()
1909 _session->begin_reversible_command (_("clear ranges"));
1910 XMLNode &before = _session->locations()->get_state();
1912 Location * looploc = _session->locations()->auto_loop_location();
1913 Location * punchloc = _session->locations()->auto_punch_location();
1914 Location * sessionloc = _session->locations()->session_range_location();
1916 _session->locations()->clear_ranges ();
1918 if (looploc) _session->locations()->add (looploc);
1919 if (punchloc) _session->locations()->add (punchloc);
1920 if (sessionloc) _session->locations()->add (sessionloc);
1922 XMLNode &after = _session->locations()->get_state();
1923 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1924 _session->commit_reversible_command ();
1929 Editor::clear_locations ()
1931 _session->begin_reversible_command (_("clear locations"));
1932 XMLNode &before = _session->locations()->get_state();
1933 _session->locations()->clear ();
1934 XMLNode &after = _session->locations()->get_state();
1935 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1936 _session->commit_reversible_command ();
1937 _session->locations()->clear ();
1941 Editor::unhide_markers ()
1943 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1944 Location *l = (*i).first;
1945 if (l->is_hidden() && l->is_mark()) {
1946 l->set_hidden(false, this);
1952 Editor::unhide_ranges ()
1954 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1955 Location *l = (*i).first;
1956 if (l->is_hidden() && l->is_range_marker()) {
1957 l->set_hidden(false, this);
1962 /* INSERT/REPLACE */
1965 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1970 RouteTimeAxisView *rtv = 0;
1971 boost::shared_ptr<Playlist> playlist;
1973 _track_canvas_viewport->window_to_canvas (x, y, wx, wy);
1976 event.type = GDK_BUTTON_RELEASE;
1977 event.button.x = wx;
1978 event.button.y = wy;
1980 where = event_frame (&event, &cx, &cy);
1982 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1983 /* clearly outside canvas area */
1987 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1988 if (tv.first == 0) {
1992 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1996 if ((playlist = rtv->playlist()) == 0) {
2002 begin_reversible_command (_("insert dragged region"));
2003 playlist->clear_changes ();
2004 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2005 _session->add_command(new StatefulDiffCommand (playlist));
2006 commit_reversible_command ();
2010 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2014 RouteTimeAxisView *dest_rtv = 0;
2015 RouteTimeAxisView *source_rtv = 0;
2017 _track_canvas_viewport->window_to_canvas (x, y, wx, wy);
2020 event.type = GDK_BUTTON_RELEASE;
2021 event.button.x = wx;
2022 event.button.y = wy;
2024 event_frame (&event, &cx, &cy);
2026 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2027 if (tv.first == 0) {
2031 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2035 /* use this drag source to add underlay to a track. But we really don't care
2036 about the Route, only the view of the route, so find it first */
2037 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2038 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2042 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2043 dest_rtv->add_underlay(source_rtv->view());
2050 Editor::insert_region_list_selection (float times)
2052 RouteTimeAxisView *tv = 0;
2053 boost::shared_ptr<Playlist> playlist;
2055 if (clicked_routeview != 0) {
2056 tv = clicked_routeview;
2057 } else if (!selection->tracks.empty()) {
2058 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2061 } else if (entered_track != 0) {
2062 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2069 if ((playlist = tv->playlist()) == 0) {
2073 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2078 begin_reversible_command (_("insert region"));
2079 playlist->clear_changes ();
2080 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2081 _session->add_command(new StatefulDiffCommand (playlist));
2082 commit_reversible_command ();
2085 /* BUILT-IN EFFECTS */
2088 Editor::reverse_selection ()
2093 /* GAIN ENVELOPE EDITING */
2096 Editor::edit_envelope ()
2103 Editor::transition_to_rolling (bool fwd)
2109 if (_session->config.get_external_sync()) {
2110 switch (Config->get_sync_source()) {
2114 /* transport controlled by the master */
2119 if (_session->is_auditioning()) {
2120 _session->cancel_audition ();
2124 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2128 Editor::play_from_start ()
2130 _session->request_locate (_session->current_start_frame(), true);
2134 Editor::play_from_edit_point ()
2136 _session->request_locate (get_preferred_edit_position(), true);
2140 Editor::play_from_edit_point_and_return ()
2142 framepos_t start_frame;
2143 framepos_t return_frame;
2145 start_frame = get_preferred_edit_position (true);
2147 if (_session->transport_rolling()) {
2148 _session->request_locate (start_frame, false);
2152 /* don't reset the return frame if its already set */
2154 if ((return_frame = _session->requested_return_frame()) < 0) {
2155 return_frame = _session->audible_frame();
2158 if (start_frame >= 0) {
2159 _session->request_roll_at_and_return (start_frame, return_frame);
2164 Editor::play_selection ()
2166 if (selection->time.empty()) {
2170 _session->request_play_range (&selection->time, true);
2174 Editor::get_preroll ()
2176 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2181 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2183 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2186 location -= get_preroll();
2188 //don't try to locate before the beginning of time
2192 //if follow_playhead is on, keep the playhead on the screen
2193 if ( _follow_playhead )
2194 if ( location < leftmost_frame )
2195 location = leftmost_frame;
2197 _session->request_locate( location );
2201 Editor::play_with_preroll ()
2203 if (selection->time.empty()) {
2206 framepos_t preroll = get_preroll();
2208 framepos_t start = 0;
2209 if (selection->time[clicked_selection].start > preroll)
2210 start = selection->time[clicked_selection].start - preroll;
2212 framepos_t end = selection->time[clicked_selection].end + preroll;
2214 AudioRange ar (start, end, 0);
2215 list<AudioRange> lar;
2218 _session->request_play_range (&lar, true);
2223 Editor::play_location (Location& location)
2225 if (location.start() <= location.end()) {
2229 _session->request_bounded_roll (location.start(), location.end());
2233 Editor::loop_location (Location& location)
2235 if (location.start() <= location.end()) {
2241 if ((tll = transport_loop_location()) != 0) {
2242 tll->set (location.start(), location.end());
2244 // enable looping, reposition and start rolling
2245 _session->request_play_loop (true);
2246 _session->request_locate (tll->start(), true);
2251 Editor::do_layer_operation (LayerOperation op)
2253 if (selection->regions.empty ()) {
2257 bool const multiple = selection->regions.size() > 1;
2261 begin_reversible_command (_("raise regions"));
2263 begin_reversible_command (_("raise region"));
2269 begin_reversible_command (_("raise regions to top"));
2271 begin_reversible_command (_("raise region to top"));
2277 begin_reversible_command (_("lower regions"));
2279 begin_reversible_command (_("lower region"));
2285 begin_reversible_command (_("lower regions to bottom"));
2287 begin_reversible_command (_("lower region"));
2292 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2293 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2294 (*i)->clear_owned_changes ();
2297 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2298 boost::shared_ptr<Region> r = (*i)->region ();
2310 r->lower_to_bottom ();
2314 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2315 vector<Command*> cmds;
2317 _session->add_commands (cmds);
2320 commit_reversible_command ();
2324 Editor::raise_region ()
2326 do_layer_operation (Raise);
2330 Editor::raise_region_to_top ()
2332 do_layer_operation (RaiseToTop);
2336 Editor::lower_region ()
2338 do_layer_operation (Lower);
2342 Editor::lower_region_to_bottom ()
2344 do_layer_operation (LowerToBottom);
2347 /** Show the region editor for the selected regions */
2349 Editor::show_region_properties ()
2351 selection->foreach_regionview (&RegionView::show_region_editor);
2354 /** Show the midi list editor for the selected MIDI regions */
2356 Editor::show_midi_list_editor ()
2358 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2362 Editor::rename_region ()
2364 RegionSelection rs = get_regions_from_selection_and_entered ();
2370 ArdourDialog d (*this, _("Rename Region"), true, false);
2372 Label label (_("New name:"));
2375 hbox.set_spacing (6);
2376 hbox.pack_start (label, false, false);
2377 hbox.pack_start (entry, true, true);
2379 d.get_vbox()->set_border_width (12);
2380 d.get_vbox()->pack_start (hbox, false, false);
2382 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2383 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2385 d.set_size_request (300, -1);
2386 d.set_position (Gtk::WIN_POS_MOUSE);
2388 entry.set_text (rs.front()->region()->name());
2389 entry.select_region (0, -1);
2391 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2397 int const ret = d.run();
2401 if (ret != RESPONSE_OK) {
2405 std::string str = entry.get_text();
2406 strip_whitespace_edges (str);
2408 rs.front()->region()->set_name (str);
2409 _regions->redisplay ();
2414 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2416 if (_session->is_auditioning()) {
2417 _session->cancel_audition ();
2420 // note: some potential for creativity here, because region doesn't
2421 // have to belong to the playlist that Route is handling
2423 // bool was_soloed = route.soloed();
2425 route.set_solo (true, this);
2427 _session->request_bounded_roll (region->position(), region->position() + region->length());
2429 /* XXX how to unset the solo state ? */
2432 /** Start an audition of the first selected region */
2434 Editor::play_edit_range ()
2436 framepos_t start, end;
2438 if (get_edit_op_range (start, end)) {
2439 _session->request_bounded_roll (start, end);
2444 Editor::play_selected_region ()
2446 framepos_t start = max_framepos;
2449 RegionSelection rs = get_regions_from_selection_and_entered ();
2455 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2456 if ((*i)->region()->position() < start) {
2457 start = (*i)->region()->position();
2459 if ((*i)->region()->last_frame() + 1 > end) {
2460 end = (*i)->region()->last_frame() + 1;
2464 _session->request_bounded_roll (start, end);
2468 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2470 _session->audition_region (region);
2474 Editor::region_from_selection ()
2476 if (clicked_axisview == 0) {
2480 if (selection->time.empty()) {
2484 framepos_t start = selection->time[clicked_selection].start;
2485 framepos_t end = selection->time[clicked_selection].end;
2487 TrackViewList tracks = get_tracks_for_range_action ();
2489 framepos_t selection_cnt = end - start + 1;
2491 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2492 boost::shared_ptr<Region> current;
2493 boost::shared_ptr<Playlist> pl;
2494 framepos_t internal_start;
2497 if ((pl = (*i)->playlist()) == 0) {
2501 if ((current = pl->top_region_at (start)) == 0) {
2505 internal_start = start - current->position();
2506 RegionFactory::region_name (new_name, current->name(), true);
2510 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2511 plist.add (ARDOUR::Properties::length, selection_cnt);
2512 plist.add (ARDOUR::Properties::name, new_name);
2513 plist.add (ARDOUR::Properties::layer, 0);
2515 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2520 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2522 if (selection->time.empty() || selection->tracks.empty()) {
2526 framepos_t start = selection->time[clicked_selection].start;
2527 framepos_t end = selection->time[clicked_selection].end;
2529 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2530 sort_track_selection (ts);
2532 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2533 boost::shared_ptr<Region> current;
2534 boost::shared_ptr<Playlist> playlist;
2535 framepos_t internal_start;
2538 if ((playlist = (*i)->playlist()) == 0) {
2542 if ((current = playlist->top_region_at(start)) == 0) {
2546 internal_start = start - current->position();
2547 RegionFactory::region_name (new_name, current->name(), true);
2551 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2552 plist.add (ARDOUR::Properties::length, end - start + 1);
2553 plist.add (ARDOUR::Properties::name, new_name);
2555 new_regions.push_back (RegionFactory::create (current, plist));
2560 Editor::split_multichannel_region ()
2562 RegionSelection rs = get_regions_from_selection_and_entered ();
2568 vector< boost::shared_ptr<Region> > v;
2570 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2571 (*x)->region()->separate_by_channel (*_session, v);
2576 Editor::new_region_from_selection ()
2578 region_from_selection ();
2579 cancel_selection ();
2583 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2585 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2586 case Evoral::OverlapNone:
2594 * - selected tracks, or if there are none...
2595 * - tracks containing selected regions, or if there are none...
2600 Editor::get_tracks_for_range_action () const
2604 if (selection->tracks.empty()) {
2606 /* use tracks with selected regions */
2608 RegionSelection rs = selection->regions;
2610 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2611 TimeAxisView* tv = &(*i)->get_time_axis_view();
2613 if (!t.contains (tv)) {
2619 /* no regions and no tracks: use all tracks */
2625 t = selection->tracks;
2628 return t.filter_to_unique_playlists();
2632 Editor::separate_regions_between (const TimeSelection& ts)
2634 bool in_command = false;
2635 boost::shared_ptr<Playlist> playlist;
2636 RegionSelection new_selection;
2638 TrackViewList tmptracks = get_tracks_for_range_action ();
2639 sort_track_selection (tmptracks);
2641 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2643 RouteTimeAxisView* rtv;
2645 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2647 if (rtv->is_track()) {
2649 /* no edits to destructive tracks */
2651 if (rtv->track()->destructive()) {
2655 if ((playlist = rtv->playlist()) != 0) {
2657 playlist->clear_changes ();
2659 /* XXX need to consider musical time selections here at some point */
2661 double speed = rtv->track()->speed();
2664 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2666 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2667 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2669 latest_regionviews.clear ();
2671 playlist->partition ((framepos_t)((*t).start * speed),
2672 (framepos_t)((*t).end * speed), false);
2676 if (!latest_regionviews.empty()) {
2678 rtv->view()->foreach_regionview (sigc::bind (
2679 sigc::ptr_fun (add_if_covered),
2680 &(*t), &new_selection));
2683 begin_reversible_command (_("separate"));
2687 /* pick up changes to existing regions */
2689 vector<Command*> cmds;
2690 playlist->rdiff (cmds);
2691 _session->add_commands (cmds);
2693 /* pick up changes to the playlist itself (adds/removes)
2696 _session->add_command(new StatefulDiffCommand (playlist));
2705 selection->set (new_selection);
2706 set_mouse_mode (MouseObject);
2708 commit_reversible_command ();
2712 struct PlaylistState {
2713 boost::shared_ptr<Playlist> playlist;
2717 /** Take tracks from get_tracks_for_range_action and cut any regions
2718 * on those tracks so that the tracks are empty over the time
2722 Editor::separate_region_from_selection ()
2724 /* preferentially use *all* ranges in the time selection if we're in range mode
2725 to allow discontiguous operation, since get_edit_op_range() currently
2726 returns a single range.
2729 if (!selection->time.empty()) {
2731 separate_regions_between (selection->time);
2738 if (get_edit_op_range (start, end)) {
2740 AudioRange ar (start, end, 1);
2744 separate_regions_between (ts);
2750 Editor::separate_region_from_punch ()
2752 Location* loc = _session->locations()->auto_punch_location();
2754 separate_regions_using_location (*loc);
2759 Editor::separate_region_from_loop ()
2761 Location* loc = _session->locations()->auto_loop_location();
2763 separate_regions_using_location (*loc);
2768 Editor::separate_regions_using_location (Location& loc)
2770 if (loc.is_mark()) {
2774 AudioRange ar (loc.start(), loc.end(), 1);
2779 separate_regions_between (ts);
2782 /** Separate regions under the selected region */
2784 Editor::separate_under_selected_regions ()
2786 vector<PlaylistState> playlists;
2790 rs = get_regions_from_selection_and_entered();
2792 if (!_session || rs.empty()) {
2796 begin_reversible_command (_("separate region under"));
2798 list<boost::shared_ptr<Region> > regions_to_remove;
2800 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2801 // we can't just remove the region(s) in this loop because
2802 // this removes them from the RegionSelection, and they thus
2803 // disappear from underneath the iterator, and the ++i above
2804 // SEGVs in a puzzling fashion.
2806 // so, first iterate over the regions to be removed from rs and
2807 // add them to the regions_to_remove list, and then
2808 // iterate over the list to actually remove them.
2810 regions_to_remove.push_back ((*i)->region());
2813 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2815 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2818 // is this check necessary?
2822 vector<PlaylistState>::iterator i;
2824 //only take state if this is a new playlist.
2825 for (i = playlists.begin(); i != playlists.end(); ++i) {
2826 if ((*i).playlist == playlist) {
2831 if (i == playlists.end()) {
2833 PlaylistState before;
2834 before.playlist = playlist;
2835 before.before = &playlist->get_state();
2837 playlist->freeze ();
2838 playlists.push_back(before);
2841 //Partition on the region bounds
2842 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2844 //Re-add region that was just removed due to the partition operation
2845 playlist->add_region( (*rl), (*rl)->first_frame() );
2848 vector<PlaylistState>::iterator pl;
2850 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2851 (*pl).playlist->thaw ();
2852 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2855 commit_reversible_command ();
2859 Editor::crop_region_to_selection ()
2861 if (!selection->time.empty()) {
2863 crop_region_to (selection->time.start(), selection->time.end_frame());
2870 if (get_edit_op_range (start, end)) {
2871 crop_region_to (start, end);
2878 Editor::crop_region_to (framepos_t start, framepos_t end)
2880 vector<boost::shared_ptr<Playlist> > playlists;
2881 boost::shared_ptr<Playlist> playlist;
2884 if (selection->tracks.empty()) {
2885 ts = track_views.filter_to_unique_playlists();
2887 ts = selection->tracks.filter_to_unique_playlists ();
2890 sort_track_selection (ts);
2892 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2894 RouteTimeAxisView* rtv;
2896 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2898 boost::shared_ptr<Track> t = rtv->track();
2900 if (t != 0 && ! t->destructive()) {
2902 if ((playlist = rtv->playlist()) != 0) {
2903 playlists.push_back (playlist);
2909 if (playlists.empty()) {
2913 framepos_t the_start;
2917 begin_reversible_command (_("trim to selection"));
2919 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2921 boost::shared_ptr<Region> region;
2925 if ((region = (*i)->top_region_at(the_start)) == 0) {
2929 /* now adjust lengths to that we do the right thing
2930 if the selection extends beyond the region
2933 the_start = max (the_start, (framepos_t) region->position());
2934 if (max_framepos - the_start < region->length()) {
2935 the_end = the_start + region->length() - 1;
2937 the_end = max_framepos;
2939 the_end = min (end, the_end);
2940 cnt = the_end - the_start + 1;
2942 region->clear_changes ();
2943 region->trim_to (the_start, cnt);
2944 _session->add_command (new StatefulDiffCommand (region));
2947 commit_reversible_command ();
2951 Editor::region_fill_track ()
2953 RegionSelection rs = get_regions_from_selection_and_entered ();
2955 if (!_session || rs.empty()) {
2959 framepos_t const end = _session->current_end_frame ();
2961 begin_reversible_command (Operations::region_fill);
2963 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2965 boost::shared_ptr<Region> region ((*i)->region());
2967 boost::shared_ptr<Playlist> pl = region->playlist();
2969 if (end <= region->last_frame()) {
2973 double times = (double) (end - region->last_frame()) / (double) region->length();
2979 pl->clear_changes ();
2980 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2981 _session->add_command (new StatefulDiffCommand (pl));
2984 commit_reversible_command ();
2988 Editor::region_fill_selection ()
2990 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2994 if (selection->time.empty()) {
2998 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3003 framepos_t start = selection->time[clicked_selection].start;
3004 framepos_t end = selection->time[clicked_selection].end;
3006 boost::shared_ptr<Playlist> playlist;
3008 if (selection->tracks.empty()) {
3012 framepos_t selection_length = end - start;
3013 float times = (float)selection_length / region->length();
3015 begin_reversible_command (Operations::fill_selection);
3017 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3019 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3021 if ((playlist = (*i)->playlist()) == 0) {
3025 playlist->clear_changes ();
3026 playlist->add_region (RegionFactory::create (region, true), start, times);
3027 _session->add_command (new StatefulDiffCommand (playlist));
3030 commit_reversible_command ();
3034 Editor::set_region_sync_position ()
3036 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3040 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3042 bool in_command = false;
3044 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3046 if (!(*r)->region()->covers (where)) {
3050 boost::shared_ptr<Region> region ((*r)->region());
3053 begin_reversible_command (_("set sync point"));
3057 region->clear_changes ();
3058 region->set_sync_position (where);
3059 _session->add_command(new StatefulDiffCommand (region));
3063 commit_reversible_command ();
3067 /** Remove the sync positions of the selection */
3069 Editor::remove_region_sync ()
3071 RegionSelection rs = get_regions_from_selection_and_entered ();
3077 begin_reversible_command (_("remove region sync"));
3079 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3081 (*i)->region()->clear_changes ();
3082 (*i)->region()->clear_sync_position ();
3083 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3086 commit_reversible_command ();
3090 Editor::naturalize_region ()
3092 RegionSelection rs = get_regions_from_selection_and_entered ();
3098 if (rs.size() > 1) {
3099 begin_reversible_command (_("move regions to original position"));
3101 begin_reversible_command (_("move region to original position"));
3104 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3105 (*i)->region()->clear_changes ();
3106 (*i)->region()->move_to_natural_position ();
3107 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3110 commit_reversible_command ();
3114 Editor::align_regions (RegionPoint what)
3116 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3122 begin_reversible_command (_("align selection"));
3124 framepos_t const position = get_preferred_edit_position ();
3126 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3127 align_region_internal ((*i)->region(), what, position);
3130 commit_reversible_command ();
3133 struct RegionSortByTime {
3134 bool operator() (const RegionView* a, const RegionView* b) {
3135 return a->region()->position() < b->region()->position();
3140 Editor::align_regions_relative (RegionPoint point)
3142 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3148 framepos_t const position = get_preferred_edit_position ();
3150 framepos_t distance = 0;
3154 list<RegionView*> sorted;
3155 rs.by_position (sorted);
3157 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3162 if (position > r->position()) {
3163 distance = position - r->position();
3165 distance = r->position() - position;
3171 if (position > r->last_frame()) {
3172 distance = position - r->last_frame();
3173 pos = r->position() + distance;
3175 distance = r->last_frame() - position;
3176 pos = r->position() - distance;
3182 pos = r->adjust_to_sync (position);
3183 if (pos > r->position()) {
3184 distance = pos - r->position();
3186 distance = r->position() - pos;
3192 if (pos == r->position()) {
3196 begin_reversible_command (_("align selection (relative)"));
3198 /* move first one specially */
3200 r->clear_changes ();
3201 r->set_position (pos);
3202 _session->add_command(new StatefulDiffCommand (r));
3204 /* move rest by the same amount */
3208 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3210 boost::shared_ptr<Region> region ((*i)->region());
3212 region->clear_changes ();
3215 region->set_position (region->position() + distance);
3217 region->set_position (region->position() - distance);
3220 _session->add_command(new StatefulDiffCommand (region));
3224 commit_reversible_command ();
3228 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3230 begin_reversible_command (_("align region"));
3231 align_region_internal (region, point, position);
3232 commit_reversible_command ();
3236 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3238 region->clear_changes ();
3242 region->set_position (region->adjust_to_sync (position));
3246 if (position > region->length()) {
3247 region->set_position (position - region->length());
3252 region->set_position (position);
3256 _session->add_command(new StatefulDiffCommand (region));
3260 Editor::trim_region_front ()
3266 Editor::trim_region_back ()
3268 trim_region (false);
3272 Editor::trim_region (bool front)
3274 framepos_t where = get_preferred_edit_position();
3275 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3281 begin_reversible_command (front ? _("trim front") : _("trim back"));
3283 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3284 if (!(*i)->region()->locked()) {
3286 (*i)->region()->clear_changes ();
3289 (*i)->region()->trim_front (where);
3290 maybe_locate_with_edit_preroll ( where );
3292 (*i)->region()->trim_end (where);
3293 maybe_locate_with_edit_preroll ( where );
3296 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3300 commit_reversible_command ();
3303 /** Trim the end of the selected regions to the position of the edit cursor */
3305 Editor::trim_region_to_loop ()
3307 Location* loc = _session->locations()->auto_loop_location();
3311 trim_region_to_location (*loc, _("trim to loop"));
3315 Editor::trim_region_to_punch ()
3317 Location* loc = _session->locations()->auto_punch_location();
3321 trim_region_to_location (*loc, _("trim to punch"));
3325 Editor::trim_region_to_location (const Location& loc, const char* str)
3327 RegionSelection rs = get_regions_from_selection_and_entered ();
3329 begin_reversible_command (str);
3331 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3332 RegionView* rv = (*x);
3334 /* require region to span proposed trim */
3335 switch (rv->region()->coverage (loc.start(), loc.end())) {
3336 case Evoral::OverlapInternal:
3342 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3351 if (tav->track() != 0) {
3352 speed = tav->track()->speed();
3355 start = session_frame_to_track_frame (loc.start(), speed);
3356 end = session_frame_to_track_frame (loc.end(), speed);
3358 rv->region()->clear_changes ();
3359 rv->region()->trim_to (start, (end - start));
3360 _session->add_command(new StatefulDiffCommand (rv->region()));
3363 commit_reversible_command ();
3367 Editor::trim_region_to_previous_region_end ()
3369 return trim_to_region(false);
3373 Editor::trim_region_to_next_region_start ()
3375 return trim_to_region(true);
3379 Editor::trim_to_region(bool forward)
3381 RegionSelection rs = get_regions_from_selection_and_entered ();
3383 begin_reversible_command (_("trim to region"));
3385 boost::shared_ptr<Region> next_region;
3387 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3389 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3395 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3403 if (atav->track() != 0) {
3404 speed = atav->track()->speed();
3408 boost::shared_ptr<Region> region = arv->region();
3409 boost::shared_ptr<Playlist> playlist (region->playlist());
3411 region->clear_changes ();
3415 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3421 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3422 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3426 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3432 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3434 arv->region_changed (ARDOUR::bounds_change);
3437 _session->add_command(new StatefulDiffCommand (region));
3440 commit_reversible_command ();
3444 Editor::unfreeze_route ()
3446 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3450 clicked_routeview->track()->unfreeze ();
3454 Editor::_freeze_thread (void* arg)
3456 return static_cast<Editor*>(arg)->freeze_thread ();
3460 Editor::freeze_thread ()
3462 /* create event pool because we may need to talk to the session */
3463 SessionEvent::create_per_thread_pool ("freeze events", 64);
3464 /* create per-thread buffers for process() tree to use */
3465 current_interthread_info->process_thread.get_buffers ();
3466 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3467 current_interthread_info->done = true;
3468 current_interthread_info->process_thread.drop_buffers();
3473 Editor::freeze_route ()
3479 /* stop transport before we start. this is important */
3481 _session->request_transport_speed (0.0);
3483 /* wait for just a little while, because the above call is asynchronous */
3487 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3491 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3493 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3494 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3496 d.set_title (_("Cannot freeze"));
3501 if (clicked_routeview->track()->has_external_redirects()) {
3502 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"
3503 "Freezing will only process the signal as far as the first send/insert/return."),
3504 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3506 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3507 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3508 d.set_title (_("Freeze Limits"));
3510 int response = d.run ();
3513 case Gtk::RESPONSE_CANCEL:
3520 InterThreadInfo itt;
3521 current_interthread_info = &itt;
3523 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3525 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3527 set_canvas_cursor (_cursors->wait);
3529 while (!itt.done && !itt.cancel) {
3530 gtk_main_iteration ();
3533 current_interthread_info = 0;
3534 set_canvas_cursor (current_canvas_cursor);
3538 Editor::bounce_range_selection (bool replace, bool enable_processing)
3540 if (selection->time.empty()) {
3544 TrackSelection views = selection->tracks;
3546 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3548 if (enable_processing) {
3550 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3552 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3554 _("You can't perform this operation because the processing of the signal "
3555 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3556 "You can do this without processing, which is a different operation.")
3558 d.set_title (_("Cannot bounce"));
3565 framepos_t start = selection->time[clicked_selection].start;
3566 framepos_t end = selection->time[clicked_selection].end;
3567 framepos_t cnt = end - start + 1;
3569 begin_reversible_command (_("bounce range"));
3571 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3573 RouteTimeAxisView* rtv;
3575 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3579 boost::shared_ptr<Playlist> playlist;
3581 if ((playlist = rtv->playlist()) == 0) {
3585 InterThreadInfo itt;
3587 playlist->clear_changes ();
3588 playlist->clear_owned_changes ();
3590 boost::shared_ptr<Region> r;
3592 if (enable_processing) {
3593 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3595 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3603 list<AudioRange> ranges;
3604 ranges.push_back (AudioRange (start, start+cnt, 0));
3605 playlist->cut (ranges); // discard result
3606 playlist->add_region (r, start);
3609 vector<Command*> cmds;
3610 playlist->rdiff (cmds);
3611 _session->add_commands (cmds);
3613 _session->add_command (new StatefulDiffCommand (playlist));
3616 commit_reversible_command ();
3619 /** Delete selected regions, automation points or a time range */
3626 /** Cut selected regions, automation points or a time range */
3633 /** Copy selected regions, automation points or a time range */
3641 /** @return true if a Cut, Copy or Clear is possible */
3643 Editor::can_cut_copy () const
3645 switch (effective_mouse_mode()) {
3648 if (!selection->regions.empty() || !selection->points.empty()) {
3654 if (!selection->time.empty()) {
3667 /** Cut, copy or clear selected regions, automation points or a time range.
3668 * @param op Operation (Cut, Copy or Clear)
3671 Editor::cut_copy (CutCopyOp op)
3673 /* only cancel selection if cut/copy is successful.*/
3679 opname = _("delete");
3688 opname = _("clear");
3692 /* if we're deleting something, and the mouse is still pressed,
3693 the thing we started a drag for will be gone when we release
3694 the mouse button(s). avoid this. see part 2 at the end of
3698 if (op == Delete || op == Cut || op == Clear) {
3699 if (_drags->active ()) {
3704 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3705 cut_buffer->clear ();
3707 if (entered_marker) {
3709 /* cut/delete op while pointing at a marker */
3712 Location* loc = find_location_from_marker (entered_marker, ignored);
3714 if (_session && loc) {
3715 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3722 if (internal_editing()) {
3724 switch (effective_mouse_mode()) {
3737 /* we only want to cut regions if some are selected */
3739 if (!selection->regions.empty()) {
3740 rs = selection->regions;
3743 switch (effective_mouse_mode()) {
3746 //find regions's gain line
3747 AudioRegionView *rview = dynamic_cast<AudioRegionView*>(clicked_regionview);
3748 AutomationTimeAxisView *tview = dynamic_cast<AutomationTimeAxisView*>(clicked_trackview);
3750 AudioRegionGainLine *line = rview->get_gain_line();
3753 //cut region gain points in the selection
3754 AutomationList& alist (line->the_list());
3755 XMLNode &before = alist.get_state();
3756 AutomationList* what_we_got = 0;
3757 if ((what_we_got = alist.cut (selection->time.front().start - rview->audio_region()->position(), selection->time.front().end - rview->audio_region()->position())) != 0) {
3758 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3763 rview->set_envelope_visible(true);
3764 rview->audio_region()->set_envelope_active(true);
3767 AutomationLine *line = *(tview->lines.begin());
3770 //cut auto points in the selection
3771 AutomationList& alist (line->the_list());
3772 XMLNode &before = alist.get_state();
3773 AutomationList* what_we_got = 0;
3774 if ((what_we_got = alist.cut (selection->time.front().start, selection->time.front().end)) != 0) {
3775 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3785 if (!rs.empty() || !selection->points.empty()) {
3786 begin_reversible_command (opname + _(" objects"));
3789 cut_copy_regions (op, rs);
3791 if (op == Cut || op == Delete) {
3792 selection->clear_regions ();
3796 if (!selection->points.empty()) {
3797 cut_copy_points (op);
3799 if (op == Cut || op == Delete) {
3800 selection->clear_points ();
3804 commit_reversible_command ();
3808 if (selection->time.empty()) {
3809 framepos_t start, end;
3810 if (!get_edit_op_range (start, end)) {
3813 selection->set (start, end);
3816 begin_reversible_command (opname + _(" range"));
3817 cut_copy_ranges (op);
3818 commit_reversible_command ();
3820 if (op == Cut || op == Delete) {
3821 selection->clear_time ();
3831 if (op == Delete || op == Cut || op == Clear) {
3836 struct AutomationRecord {
3837 AutomationRecord () : state (0) {}
3838 AutomationRecord (XMLNode* s) : state (s) {}
3840 XMLNode* state; ///< state before any operation
3841 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3844 /** Cut, copy or clear selected automation points.
3845 * @param op Operation (Cut, Copy or Clear)
3848 Editor::cut_copy_points (CutCopyOp op)
3850 if (selection->points.empty ()) {
3854 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3855 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3857 /* Keep a record of the AutomationLists that we end up using in this operation */
3858 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3861 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3862 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3863 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3864 if (lists.find (al) == lists.end ()) {
3865 /* We haven't seen this list yet, so make a record for it. This includes
3866 taking a copy of its current state, in case this is needed for undo later.
3868 lists[al] = AutomationRecord (&al->get_state ());
3872 if (op == Cut || op == Copy) {
3873 /* This operation will involve putting things in the cut buffer, so create an empty
3874 ControlList for each of our source lists to put the cut buffer data in.
3876 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3877 i->second.copy = i->first->create (i->first->parameter ());
3880 /* Add all selected points to the relevant copy ControlLists */
3881 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3882 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3883 AutomationList::const_iterator j = (*i)->model ();
3884 lists[al].copy->add ((*j)->when, (*j)->value);
3887 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3888 /* Correct this copy list so that it starts at time 0 */
3889 double const start = i->second.copy->front()->when;
3890 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3891 (*j)->when -= start;
3894 /* And add it to the cut buffer */
3895 cut_buffer->add (i->second.copy);
3899 if (op == Delete || op == Cut) {
3900 /* This operation needs to remove things from the main AutomationList, so do that now */
3902 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3903 i->first->freeze ();
3906 /* Remove each selected point from its AutomationList */
3907 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3908 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3909 al->erase ((*i)->model ());
3912 /* Thaw the lists and add undo records for them */
3913 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3914 boost::shared_ptr<AutomationList> al = i->first;
3916 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3921 /** Cut, copy or clear selected automation points.
3922 * @param op Operation (Cut, Copy or Clear)
3925 Editor::cut_copy_midi (CutCopyOp op)
3927 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3928 MidiRegionView* mrv = *i;
3929 mrv->cut_copy_clear (op);
3935 struct lt_playlist {
3936 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3937 return a.playlist < b.playlist;
3941 struct PlaylistMapping {
3943 boost::shared_ptr<Playlist> pl;
3945 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3948 /** Remove `clicked_regionview' */
3950 Editor::remove_clicked_region ()
3952 if (clicked_routeview == 0 || clicked_regionview == 0) {
3956 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3958 begin_reversible_command (_("remove region"));
3959 playlist->clear_changes ();
3960 playlist->clear_owned_changes ();
3961 playlist->remove_region (clicked_regionview->region());
3963 /* We might have removed regions, which alters other regions' layering_index,
3964 so we need to do a recursive diff here.
3966 vector<Command*> cmds;
3967 playlist->rdiff (cmds);
3968 _session->add_commands (cmds);
3970 _session->add_command(new StatefulDiffCommand (playlist));
3971 commit_reversible_command ();
3975 /** Remove the selected regions */
3977 Editor::remove_selected_regions ()
3979 RegionSelection rs = get_regions_from_selection_and_entered ();
3981 if (!_session || rs.empty()) {
3985 begin_reversible_command (_("remove region"));
3987 list<boost::shared_ptr<Region> > regions_to_remove;
3989 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3990 // we can't just remove the region(s) in this loop because
3991 // this removes them from the RegionSelection, and they thus
3992 // disappear from underneath the iterator, and the ++i above
3993 // SEGVs in a puzzling fashion.
3995 // so, first iterate over the regions to be removed from rs and
3996 // add them to the regions_to_remove list, and then
3997 // iterate over the list to actually remove them.
3999 regions_to_remove.push_back ((*i)->region());
4002 vector<boost::shared_ptr<Playlist> > playlists;
4004 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4006 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4009 // is this check necessary?
4013 /* get_regions_from_selection_and_entered() guarantees that
4014 the playlists involved are unique, so there is no need
4018 playlists.push_back (playlist);
4020 playlist->clear_changes ();
4021 playlist->clear_owned_changes ();
4022 playlist->freeze ();
4023 playlist->remove_region (*rl);
4026 vector<boost::shared_ptr<Playlist> >::iterator pl;
4028 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4031 /* We might have removed regions, which alters other regions' layering_index,
4032 so we need to do a recursive diff here.
4034 vector<Command*> cmds;
4035 (*pl)->rdiff (cmds);
4036 _session->add_commands (cmds);
4038 _session->add_command(new StatefulDiffCommand (*pl));
4041 commit_reversible_command ();
4044 /** Cut, copy or clear selected regions.
4045 * @param op Operation (Cut, Copy or Clear)
4048 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4050 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4051 a map when we want ordered access to both elements. i think.
4054 vector<PlaylistMapping> pmap;
4056 framepos_t first_position = max_framepos;
4058 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4059 FreezeList freezelist;
4061 /* get ordering correct before we cut/copy */
4063 rs.sort_by_position_and_track ();
4065 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4067 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4069 if (op == Cut || op == Clear || op == Delete) {
4070 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4073 FreezeList::iterator fl;
4075 // only take state if this is a new playlist.
4076 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4082 if (fl == freezelist.end()) {
4083 pl->clear_changes();
4084 pl->clear_owned_changes ();
4086 freezelist.insert (pl);
4091 TimeAxisView* tv = &(*x)->get_time_axis_view();
4092 vector<PlaylistMapping>::iterator z;
4094 for (z = pmap.begin(); z != pmap.end(); ++z) {
4095 if ((*z).tv == tv) {
4100 if (z == pmap.end()) {
4101 pmap.push_back (PlaylistMapping (tv));
4105 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4107 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4110 /* region not yet associated with a playlist (e.g. unfinished
4117 TimeAxisView& tv = (*x)->get_time_axis_view();
4118 boost::shared_ptr<Playlist> npl;
4119 RegionSelection::iterator tmp;
4126 vector<PlaylistMapping>::iterator z;
4128 for (z = pmap.begin(); z != pmap.end(); ++z) {
4129 if ((*z).tv == &tv) {
4134 assert (z != pmap.end());
4137 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4145 boost::shared_ptr<Region> r = (*x)->region();
4146 boost::shared_ptr<Region> _xx;
4152 pl->remove_region (r);
4156 _xx = RegionFactory::create (r);
4157 npl->add_region (_xx, r->position() - first_position);
4158 pl->remove_region (r);
4162 /* copy region before adding, so we're not putting same object into two different playlists */
4163 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4167 pl->remove_region (r);
4176 list<boost::shared_ptr<Playlist> > foo;
4178 /* the pmap is in the same order as the tracks in which selected regions occured */
4180 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4183 foo.push_back ((*i).pl);
4188 cut_buffer->set (foo);
4192 _last_cut_copy_source_track = 0;
4194 _last_cut_copy_source_track = pmap.front().tv;
4198 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4201 /* We might have removed regions, which alters other regions' layering_index,
4202 so we need to do a recursive diff here.
4204 vector<Command*> cmds;
4205 (*pl)->rdiff (cmds);
4206 _session->add_commands (cmds);
4208 _session->add_command (new StatefulDiffCommand (*pl));
4213 Editor::cut_copy_ranges (CutCopyOp op)
4215 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4217 /* Sort the track selection now, so that it if is used, the playlists
4218 selected by the calls below to cut_copy_clear are in the order that
4219 their tracks appear in the editor. This makes things like paste
4220 of ranges work properly.
4223 sort_track_selection (ts);
4226 if (!entered_track) {
4229 ts.push_back (entered_track);
4232 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4233 (*i)->cut_copy_clear (*selection, op);
4238 Editor::paste (float times, bool from_context)
4240 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4242 paste_internal (get_preferred_edit_position (false, from_context), times);
4246 Editor::mouse_paste ()
4251 if (!mouse_frame (where, ignored)) {
4256 paste_internal (where, 1);
4260 Editor::paste_internal (framepos_t position, float times)
4262 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4264 if (internal_editing()) {
4265 if (cut_buffer->midi_notes.empty()) {
4269 if (cut_buffer->empty()) {
4274 if (position == max_framepos) {
4275 position = get_preferred_edit_position();
4276 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4280 TrackViewList::iterator i;
4283 /* get everything in the correct order */
4285 if (_edit_point == Editing::EditAtMouse && entered_track) {
4286 /* With the mouse edit point, paste onto the track under the mouse */
4287 ts.push_back (entered_track);
4288 } else if (!selection->tracks.empty()) {
4289 /* Otherwise, if there are some selected tracks, paste to them */
4290 ts = selection->tracks.filter_to_unique_playlists ();
4291 sort_track_selection (ts);
4292 } else if (_last_cut_copy_source_track) {
4293 /* Otherwise paste to the track that the cut/copy came from;
4294 see discussion in mantis #3333.
4296 ts.push_back (_last_cut_copy_source_track);
4299 if (internal_editing ()) {
4301 /* undo/redo is handled by individual tracks/regions */
4303 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4306 RegionSelection::iterator r;
4307 MidiNoteSelection::iterator cb;
4309 get_regions_at (rs, position, ts);
4311 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4312 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4313 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4315 mrv->paste (position, times, **cb);
4323 /* we do redo (do you do voodoo?) */
4325 begin_reversible_command (Operations::paste);
4327 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4328 (*i)->paste (position, times, *cut_buffer, nth);
4331 commit_reversible_command ();
4336 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4338 boost::shared_ptr<Playlist> playlist;
4339 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4340 RegionSelection foo;
4342 framepos_t const start_frame = regions.start ();
4343 framepos_t const end_frame = regions.end_frame ();
4345 begin_reversible_command (Operations::duplicate_region);
4347 selection->clear_regions ();
4349 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4351 boost::shared_ptr<Region> r ((*i)->region());
4353 TimeAxisView& tv = (*i)->get_time_axis_view();
4354 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4355 latest_regionviews.clear ();
4356 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4358 playlist = (*i)->region()->playlist();
4359 playlist->clear_changes ();
4360 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4361 _session->add_command(new StatefulDiffCommand (playlist));
4365 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4368 commit_reversible_command ();
4371 selection->set (foo);
4376 Editor::duplicate_selection (float times)
4378 if (selection->time.empty() || selection->tracks.empty()) {
4382 boost::shared_ptr<Playlist> playlist;
4383 vector<boost::shared_ptr<Region> > new_regions;
4384 vector<boost::shared_ptr<Region> >::iterator ri;
4386 create_region_from_selection (new_regions);
4388 if (new_regions.empty()) {
4392 begin_reversible_command (_("duplicate selection"));
4394 ri = new_regions.begin();
4396 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4398 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4399 if ((playlist = (*i)->playlist()) == 0) {
4402 playlist->clear_changes ();
4403 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4404 _session->add_command (new StatefulDiffCommand (playlist));
4407 if (ri == new_regions.end()) {
4412 commit_reversible_command ();
4415 /** Reset all selected points to the relevant default value */
4417 Editor::reset_point_selection ()
4419 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4420 ARDOUR::AutomationList::iterator j = (*i)->model ();
4421 (*j)->value = (*i)->line().the_list()->default_value ();
4426 Editor::center_playhead ()
4428 float const page = _visible_canvas_width * frames_per_pixel;
4429 center_screen_internal (playhead_cursor->current_frame (), page);
4433 Editor::center_edit_point ()
4435 float const page = _visible_canvas_width * frames_per_pixel;
4436 center_screen_internal (get_preferred_edit_position(), page);
4439 /** Caller must begin and commit a reversible command */
4441 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4443 playlist->clear_changes ();
4445 _session->add_command (new StatefulDiffCommand (playlist));
4449 Editor::nudge_track (bool use_edit, bool forwards)
4451 boost::shared_ptr<Playlist> playlist;
4452 framepos_t distance;
4453 framepos_t next_distance;
4457 start = get_preferred_edit_position();
4462 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4466 if (selection->tracks.empty()) {
4470 begin_reversible_command (_("nudge track"));
4472 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4474 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4476 if ((playlist = (*i)->playlist()) == 0) {
4480 playlist->clear_changes ();
4481 playlist->clear_owned_changes ();
4483 playlist->nudge_after (start, distance, forwards);
4485 vector<Command*> cmds;
4487 playlist->rdiff (cmds);
4488 _session->add_commands (cmds);
4490 _session->add_command (new StatefulDiffCommand (playlist));
4493 commit_reversible_command ();
4497 Editor::remove_last_capture ()
4499 vector<string> choices;
4506 if (Config->get_verify_remove_last_capture()) {
4507 prompt = _("Do you really want to destroy the last capture?"
4508 "\n(This is destructive and cannot be undone)");
4510 choices.push_back (_("No, do nothing."));
4511 choices.push_back (_("Yes, destroy it."));
4513 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4515 if (prompter.run () == 1) {
4516 _session->remove_last_capture ();
4517 _regions->redisplay ();
4521 _session->remove_last_capture();
4522 _regions->redisplay ();
4527 Editor::normalize_region ()
4533 RegionSelection rs = get_regions_from_selection_and_entered ();
4539 NormalizeDialog dialog (rs.size() > 1);
4541 if (dialog.run () == RESPONSE_CANCEL) {
4545 set_canvas_cursor (_cursors->wait);
4548 /* XXX: should really only count audio regions here */
4549 int const regions = rs.size ();
4551 /* Make a list of the selected audio regions' maximum amplitudes, and also
4552 obtain the maximum amplitude of them all.
4554 list<double> max_amps;
4556 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4557 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4559 dialog.descend (1.0 / regions);
4560 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4563 /* the user cancelled the operation */
4564 set_canvas_cursor (current_canvas_cursor);
4568 max_amps.push_back (a);
4569 max_amp = max (max_amp, a);
4574 begin_reversible_command (_("normalize"));
4576 list<double>::const_iterator a = max_amps.begin ();
4578 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4579 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4584 arv->region()->clear_changes ();
4586 double const amp = dialog.normalize_individually() ? *a : max_amp;
4588 arv->audio_region()->normalize (amp, dialog.target ());
4589 _session->add_command (new StatefulDiffCommand (arv->region()));
4594 commit_reversible_command ();
4595 set_canvas_cursor (current_canvas_cursor);
4600 Editor::reset_region_scale_amplitude ()
4606 RegionSelection rs = get_regions_from_selection_and_entered ();
4612 begin_reversible_command ("reset gain");
4614 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4615 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4618 arv->region()->clear_changes ();
4619 arv->audio_region()->set_scale_amplitude (1.0f);
4620 _session->add_command (new StatefulDiffCommand (arv->region()));
4623 commit_reversible_command ();
4627 Editor::adjust_region_gain (bool up)
4629 RegionSelection rs = get_regions_from_selection_and_entered ();
4631 if (!_session || rs.empty()) {
4635 begin_reversible_command ("adjust region gain");
4637 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4638 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4643 arv->region()->clear_changes ();
4645 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4653 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4654 _session->add_command (new StatefulDiffCommand (arv->region()));
4657 commit_reversible_command ();
4662 Editor::reverse_region ()
4668 Reverse rev (*_session);
4669 apply_filter (rev, _("reverse regions"));
4673 Editor::strip_region_silence ()
4679 RegionSelection rs = get_regions_from_selection_and_entered ();
4685 std::list<RegionView*> audio_only;
4687 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4688 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4690 audio_only.push_back (arv);
4694 StripSilenceDialog d (_session, audio_only);
4695 int const r = d.run ();
4699 if (r == Gtk::RESPONSE_OK) {
4700 ARDOUR::AudioIntervalMap silences;
4701 d.silences (silences);
4702 StripSilence s (*_session, silences, d.fade_length());
4703 apply_filter (s, _("strip silence"), &d);
4708 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4710 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4711 mrv.selection_as_notelist (selected, true);
4713 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4714 v.push_back (selected);
4716 framepos_t pos_frames = mrv.midi_region()->position();
4717 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4719 return op (mrv.midi_region()->model(), pos_beats, v);
4723 Editor::apply_midi_note_edit_op (MidiOperator& op)
4727 RegionSelection rs = get_regions_from_selection_and_entered ();
4733 begin_reversible_command (op.name ());
4735 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4736 RegionSelection::iterator tmp = r;
4739 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4742 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4745 _session->add_command (cmd);
4752 commit_reversible_command ();
4756 Editor::fork_region ()
4758 RegionSelection rs = get_regions_from_selection_and_entered ();
4764 begin_reversible_command (_("Fork Region(s)"));
4766 set_canvas_cursor (_cursors->wait);
4769 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4770 RegionSelection::iterator tmp = r;
4773 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4776 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4777 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4779 playlist->clear_changes ();
4780 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4781 _session->add_command(new StatefulDiffCommand (playlist));
4787 commit_reversible_command ();
4789 set_canvas_cursor (current_canvas_cursor);
4793 Editor::quantize_region ()
4795 int selected_midi_region_cnt = 0;
4801 RegionSelection rs = get_regions_from_selection_and_entered ();
4807 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4808 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4810 selected_midi_region_cnt++;
4814 if (selected_midi_region_cnt == 0) {
4818 QuantizeDialog* qd = new QuantizeDialog (*this);
4821 const int r = qd->run ();
4824 if (r == Gtk::RESPONSE_OK) {
4825 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4826 qd->start_grid_size(), qd->end_grid_size(),
4827 qd->strength(), qd->swing(), qd->threshold());
4829 apply_midi_note_edit_op (quant);
4834 Editor::insert_patch_change (bool from_context)
4836 RegionSelection rs = get_regions_from_selection_and_entered ();
4842 const framepos_t p = get_preferred_edit_position (false, from_context);
4844 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4845 there may be more than one, but the PatchChangeDialog can only offer
4846 one set of patch menus.
4848 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4850 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4851 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4853 if (d.run() == RESPONSE_CANCEL) {
4857 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4858 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4860 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4861 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4868 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4870 RegionSelection rs = get_regions_from_selection_and_entered ();
4876 begin_reversible_command (command);
4878 set_canvas_cursor (_cursors->wait);
4882 int const N = rs.size ();
4884 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4885 RegionSelection::iterator tmp = r;
4888 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4890 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4893 progress->descend (1.0 / N);
4896 if (arv->audio_region()->apply (filter, progress) == 0) {
4898 playlist->clear_changes ();
4899 playlist->clear_owned_changes ();
4901 if (filter.results.empty ()) {
4903 /* no regions returned; remove the old one */
4904 playlist->remove_region (arv->region ());
4908 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4910 /* first region replaces the old one */
4911 playlist->replace_region (arv->region(), *res, (*res)->position());
4915 while (res != filter.results.end()) {
4916 playlist->add_region (*res, (*res)->position());
4922 /* We might have removed regions, which alters other regions' layering_index,
4923 so we need to do a recursive diff here.
4925 vector<Command*> cmds;
4926 playlist->rdiff (cmds);
4927 _session->add_commands (cmds);
4929 _session->add_command(new StatefulDiffCommand (playlist));
4935 progress->ascend ();
4943 commit_reversible_command ();
4946 set_canvas_cursor (current_canvas_cursor);
4950 Editor::external_edit_region ()
4956 Editor::reset_region_gain_envelopes ()
4958 RegionSelection rs = get_regions_from_selection_and_entered ();
4960 if (!_session || rs.empty()) {
4964 _session->begin_reversible_command (_("reset region gain"));
4966 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4967 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4969 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4970 XMLNode& before (alist->get_state());
4972 arv->audio_region()->set_default_envelope ();
4973 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4977 _session->commit_reversible_command ();
4981 Editor::set_region_gain_visibility (RegionView* rv)
4983 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4985 arv->update_envelope_visibility();
4990 Editor::set_gain_envelope_visibility ()
4996 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4997 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4999 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5005 Editor::toggle_gain_envelope_active ()
5007 if (_ignore_region_action) {
5011 RegionSelection rs = get_regions_from_selection_and_entered ();
5013 if (!_session || rs.empty()) {
5017 _session->begin_reversible_command (_("region gain envelope active"));
5019 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5020 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5022 arv->region()->clear_changes ();
5023 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5024 _session->add_command (new StatefulDiffCommand (arv->region()));
5028 _session->commit_reversible_command ();
5032 Editor::toggle_region_lock ()
5034 if (_ignore_region_action) {
5038 RegionSelection rs = get_regions_from_selection_and_entered ();
5040 if (!_session || rs.empty()) {
5044 _session->begin_reversible_command (_("toggle region lock"));
5046 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5047 (*i)->region()->clear_changes ();
5048 (*i)->region()->set_locked (!(*i)->region()->locked());
5049 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5052 _session->commit_reversible_command ();
5056 Editor::toggle_region_video_lock ()
5058 if (_ignore_region_action) {
5062 RegionSelection rs = get_regions_from_selection_and_entered ();
5064 if (!_session || rs.empty()) {
5068 _session->begin_reversible_command (_("Toggle Video Lock"));
5070 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5071 (*i)->region()->clear_changes ();
5072 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5073 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5076 _session->commit_reversible_command ();
5080 Editor::toggle_region_lock_style ()
5082 if (_ignore_region_action) {
5086 RegionSelection rs = get_regions_from_selection_and_entered ();
5088 if (!_session || rs.empty()) {
5092 _session->begin_reversible_command (_("region lock style"));
5094 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5095 (*i)->region()->clear_changes ();
5096 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5097 (*i)->region()->set_position_lock_style (ns);
5098 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5101 _session->commit_reversible_command ();
5105 Editor::toggle_opaque_region ()
5107 if (_ignore_region_action) {
5111 RegionSelection rs = get_regions_from_selection_and_entered ();
5113 if (!_session || rs.empty()) {
5117 _session->begin_reversible_command (_("change region opacity"));
5119 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5120 (*i)->region()->clear_changes ();
5121 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5122 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5125 _session->commit_reversible_command ();
5129 Editor::toggle_record_enable ()
5131 bool new_state = false;
5133 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5134 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5137 if (!rtav->is_track())
5141 new_state = !rtav->track()->record_enabled();
5145 rtav->track()->set_record_enabled (new_state, this);
5150 Editor::toggle_solo ()
5152 bool new_state = false;
5154 boost::shared_ptr<RouteList> rl (new RouteList);
5156 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5157 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5164 new_state = !rtav->route()->soloed ();
5168 rl->push_back (rtav->route());
5171 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5175 Editor::toggle_mute ()
5177 bool new_state = false;
5179 boost::shared_ptr<RouteList> rl (new RouteList);
5181 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5182 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5189 new_state = !rtav->route()->muted();
5193 rl->push_back (rtav->route());
5196 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5200 Editor::toggle_solo_isolate ()
5205 Editor::set_fade_length (bool in)
5207 RegionSelection rs = get_regions_from_selection_and_entered ();
5213 /* we need a region to measure the offset from the start */
5215 RegionView* rv = rs.front ();
5217 framepos_t pos = get_preferred_edit_position();
5221 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5222 /* edit point is outside the relevant region */
5227 if (pos <= rv->region()->position()) {
5231 len = pos - rv->region()->position();
5232 cmd = _("set fade in length");
5234 if (pos >= rv->region()->last_frame()) {
5238 len = rv->region()->last_frame() - pos;
5239 cmd = _("set fade out length");
5242 begin_reversible_command (cmd);
5244 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5245 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5251 boost::shared_ptr<AutomationList> alist;
5253 alist = tmp->audio_region()->fade_in();
5255 alist = tmp->audio_region()->fade_out();
5258 XMLNode &before = alist->get_state();
5261 tmp->audio_region()->set_fade_in_length (len);
5262 tmp->audio_region()->set_fade_in_active (true);
5264 tmp->audio_region()->set_fade_out_length (len);
5265 tmp->audio_region()->set_fade_out_active (true);
5268 XMLNode &after = alist->get_state();
5269 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5272 commit_reversible_command ();
5276 Editor::set_fade_in_shape (FadeShape shape)
5278 RegionSelection rs = get_regions_from_selection_and_entered ();
5284 begin_reversible_command (_("set fade in shape"));
5286 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5287 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5293 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5294 XMLNode &before = alist->get_state();
5296 tmp->audio_region()->set_fade_in_shape (shape);
5298 XMLNode &after = alist->get_state();
5299 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5302 commit_reversible_command ();
5307 Editor::set_fade_out_shape (FadeShape shape)
5309 RegionSelection rs = get_regions_from_selection_and_entered ();
5315 begin_reversible_command (_("set fade out shape"));
5317 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5318 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5324 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5325 XMLNode &before = alist->get_state();
5327 tmp->audio_region()->set_fade_out_shape (shape);
5329 XMLNode &after = alist->get_state();
5330 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5333 commit_reversible_command ();
5337 Editor::set_fade_in_active (bool yn)
5339 RegionSelection rs = get_regions_from_selection_and_entered ();
5345 begin_reversible_command (_("set fade in active"));
5347 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5348 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5355 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5357 ar->clear_changes ();
5358 ar->set_fade_in_active (yn);
5359 _session->add_command (new StatefulDiffCommand (ar));
5362 commit_reversible_command ();
5366 Editor::set_fade_out_active (bool yn)
5368 RegionSelection rs = get_regions_from_selection_and_entered ();
5374 begin_reversible_command (_("set fade out active"));
5376 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5377 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5383 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5385 ar->clear_changes ();
5386 ar->set_fade_out_active (yn);
5387 _session->add_command(new StatefulDiffCommand (ar));
5390 commit_reversible_command ();
5394 Editor::toggle_region_fades (int dir)
5396 if (_ignore_region_action) {
5400 boost::shared_ptr<AudioRegion> ar;
5403 RegionSelection rs = get_regions_from_selection_and_entered ();
5409 RegionSelection::iterator i;
5410 for (i = rs.begin(); i != rs.end(); ++i) {
5411 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5413 yn = ar->fade_out_active ();
5415 yn = ar->fade_in_active ();
5421 if (i == rs.end()) {
5425 /* XXX should this undo-able? */
5427 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5428 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5431 if (dir == 1 || dir == 0) {
5432 ar->set_fade_in_active (!yn);
5435 if (dir == -1 || dir == 0) {
5436 ar->set_fade_out_active (!yn);
5442 /** Update region fade visibility after its configuration has been changed */
5444 Editor::update_region_fade_visibility ()
5446 bool _fade_visibility = _session->config.get_show_region_fades ();
5448 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5449 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5451 if (_fade_visibility) {
5452 v->audio_view()->show_all_fades ();
5454 v->audio_view()->hide_all_fades ();
5461 Editor::set_edit_point ()
5466 if (!mouse_frame (where, ignored)) {
5472 if (selection->markers.empty()) {
5474 mouse_add_new_marker (where);
5479 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5482 loc->move_to (where);
5488 Editor::set_playhead_cursor ()
5490 if (entered_marker) {
5491 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5496 if (!mouse_frame (where, ignored)) {
5503 _session->request_locate (where, _session->transport_rolling());
5507 if ( Config->get_always_play_range() )
5508 cancel_time_selection();
5512 Editor::split_region ()
5514 if ( !selection->time.empty()) {
5515 separate_regions_between (selection->time);
5519 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5521 framepos_t where = get_preferred_edit_position ();
5527 split_regions_at (where, rs);
5530 struct EditorOrderRouteSorter {
5531 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5532 return a->order_key (EditorSort) < b->order_key (EditorSort);
5537 Editor::select_next_route()
5539 if (selection->tracks.empty()) {
5540 selection->set (track_views.front());
5544 TimeAxisView* current = selection->tracks.front();
5548 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5549 if (*i == current) {
5551 if (i != track_views.end()) {
5554 current = (*(track_views.begin()));
5555 //selection->set (*(track_views.begin()));
5560 rui = dynamic_cast<RouteUI *>(current);
5561 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5563 selection->set(current);
5565 ensure_track_visible(current);
5569 Editor::select_prev_route()
5571 if (selection->tracks.empty()) {
5572 selection->set (track_views.front());
5576 TimeAxisView* current = selection->tracks.front();
5580 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5581 if (*i == current) {
5583 if (i != track_views.rend()) {
5586 current = *(track_views.rbegin());
5591 rui = dynamic_cast<RouteUI *>(current);
5592 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5594 selection->set (current);
5596 ensure_track_visible(current);
5600 Editor::ensure_track_visible(TimeAxisView *track)
5602 if (track->hidden())
5605 double const current_view_min_y = vertical_adjustment.get_value();
5606 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5608 double const track_min_y = track->y_position ();
5609 double const track_max_y = track->y_position () + track->effective_height ();
5611 if (track_min_y >= current_view_min_y &&
5612 track_max_y <= current_view_max_y) {
5618 if (track_min_y < current_view_min_y) {
5619 // Track is above the current view
5620 new_value = track_min_y;
5622 // Track is below the current view
5623 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5626 vertical_adjustment.set_value(new_value);
5630 Editor::set_loop_from_selection (bool play)
5632 if (_session == 0 || selection->time.empty()) {
5636 framepos_t start = selection->time[clicked_selection].start;
5637 framepos_t end = selection->time[clicked_selection].end;
5639 set_loop_range (start, end, _("set loop range from selection"));
5642 _session->request_play_loop (true);
5643 _session->request_locate (start, true);
5648 Editor::set_loop_from_edit_range (bool play)
5650 if (_session == 0) {
5657 if (!get_edit_op_range (start, end)) {
5661 set_loop_range (start, end, _("set loop range from edit range"));
5664 _session->request_play_loop (true);
5665 _session->request_locate (start, true);
5670 Editor::set_loop_from_region (bool play)
5672 framepos_t start = max_framepos;
5675 RegionSelection rs = get_regions_from_selection_and_entered ();
5681 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5682 if ((*i)->region()->position() < start) {
5683 start = (*i)->region()->position();
5685 if ((*i)->region()->last_frame() + 1 > end) {
5686 end = (*i)->region()->last_frame() + 1;
5690 set_loop_range (start, end, _("set loop range from region"));
5693 _session->request_play_loop (true);
5694 _session->request_locate (start, true);
5699 Editor::set_punch_from_selection ()
5701 if (_session == 0 || selection->time.empty()) {
5705 framepos_t start = selection->time[clicked_selection].start;
5706 framepos_t end = selection->time[clicked_selection].end;
5708 set_punch_range (start, end, _("set punch range from selection"));
5712 Editor::set_punch_from_edit_range ()
5714 if (_session == 0) {
5721 if (!get_edit_op_range (start, end)) {
5725 set_punch_range (start, end, _("set punch range from edit range"));
5729 Editor::set_punch_from_region ()
5731 framepos_t start = max_framepos;
5734 RegionSelection rs = get_regions_from_selection_and_entered ();
5740 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5741 if ((*i)->region()->position() < start) {
5742 start = (*i)->region()->position();
5744 if ((*i)->region()->last_frame() + 1 > end) {
5745 end = (*i)->region()->last_frame() + 1;
5749 set_punch_range (start, end, _("set punch range from region"));
5753 Editor::pitch_shift_region ()
5755 RegionSelection rs = get_regions_from_selection_and_entered ();
5757 RegionSelection audio_rs;
5758 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5759 if (dynamic_cast<AudioRegionView*> (*i)) {
5760 audio_rs.push_back (*i);
5764 if (audio_rs.empty()) {
5768 pitch_shift (audio_rs, 1.2);
5772 Editor::transpose_region ()
5774 RegionSelection rs = get_regions_from_selection_and_entered ();
5776 list<MidiRegionView*> midi_region_views;
5777 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5778 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5780 midi_region_views.push_back (mrv);
5785 int const r = d.run ();
5786 if (r != RESPONSE_ACCEPT) {
5790 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5791 (*i)->midi_region()->transpose (d.semitones ());
5796 Editor::set_tempo_from_region ()
5798 RegionSelection rs = get_regions_from_selection_and_entered ();
5800 if (!_session || rs.empty()) {
5804 RegionView* rv = rs.front();
5806 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5810 Editor::use_range_as_bar ()
5812 framepos_t start, end;
5813 if (get_edit_op_range (start, end)) {
5814 define_one_bar (start, end);
5819 Editor::define_one_bar (framepos_t start, framepos_t end)
5821 framepos_t length = end - start;
5823 const Meter& m (_session->tempo_map().meter_at (start));
5825 /* length = 1 bar */
5827 /* now we want frames per beat.
5828 we have frames per bar, and beats per bar, so ...
5831 /* XXXX METER MATH */
5833 double frames_per_beat = length / m.divisions_per_bar();
5835 /* beats per minute = */
5837 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5839 /* now decide whether to:
5841 (a) set global tempo
5842 (b) add a new tempo marker
5846 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5848 bool do_global = false;
5850 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5852 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5853 at the start, or create a new marker
5856 vector<string> options;
5857 options.push_back (_("Cancel"));
5858 options.push_back (_("Add new marker"));
5859 options.push_back (_("Set global tempo"));
5862 _("Define one bar"),
5863 _("Do you want to set the global tempo or add a new tempo marker?"),
5867 c.set_default_response (2);
5883 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5884 if the marker is at the region starter, change it, otherwise add
5889 begin_reversible_command (_("set tempo from region"));
5890 XMLNode& before (_session->tempo_map().get_state());
5893 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5894 } else if (t.frame() == start) {
5895 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5897 Timecode::BBT_Time bbt;
5898 _session->tempo_map().bbt_time (start, bbt);
5899 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5902 XMLNode& after (_session->tempo_map().get_state());
5904 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5905 commit_reversible_command ();
5909 Editor::split_region_at_transients ()
5911 AnalysisFeatureList positions;
5913 RegionSelection rs = get_regions_from_selection_and_entered ();
5915 if (!_session || rs.empty()) {
5919 _session->begin_reversible_command (_("split regions"));
5921 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5923 RegionSelection::iterator tmp;
5928 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5930 if (ar && (ar->get_transients (positions) == 0)) {
5931 split_region_at_points ((*i)->region(), positions, true);
5938 _session->commit_reversible_command ();
5943 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5945 bool use_rhythmic_rodent = false;
5947 boost::shared_ptr<Playlist> pl = r->playlist();
5949 list<boost::shared_ptr<Region> > new_regions;
5955 if (positions.empty()) {
5960 if (positions.size() > 20 && can_ferret) {
5961 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);
5962 MessageDialog msg (msgstr,
5965 Gtk::BUTTONS_OK_CANCEL);
5968 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5969 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5971 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5974 msg.set_title (_("Excessive split?"));
5977 int response = msg.run();
5983 case RESPONSE_APPLY:
5984 use_rhythmic_rodent = true;
5991 if (use_rhythmic_rodent) {
5992 show_rhythm_ferret ();
5996 AnalysisFeatureList::const_iterator x;
5998 pl->clear_changes ();
5999 pl->clear_owned_changes ();
6001 x = positions.begin();
6003 if (x == positions.end()) {
6008 pl->remove_region (r);
6012 while (x != positions.end()) {
6014 /* deal with positons that are out of scope of present region bounds */
6015 if (*x <= 0 || *x > r->length()) {
6020 /* file start = original start + how far we from the initial position ?
6023 framepos_t file_start = r->start() + pos;
6025 /* length = next position - current position
6028 framepos_t len = (*x) - pos;
6030 /* XXX we do we really want to allow even single-sample regions?
6031 shouldn't we have some kind of lower limit on region size?
6040 if (RegionFactory::region_name (new_name, r->name())) {
6044 /* do NOT announce new regions 1 by one, just wait till they are all done */
6048 plist.add (ARDOUR::Properties::start, file_start);
6049 plist.add (ARDOUR::Properties::length, len);
6050 plist.add (ARDOUR::Properties::name, new_name);
6051 plist.add (ARDOUR::Properties::layer, 0);
6053 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6054 /* because we set annouce to false, manually add the new region to the
6057 RegionFactory::map_add (nr);
6059 pl->add_region (nr, r->position() + pos);
6062 new_regions.push_front(nr);
6071 RegionFactory::region_name (new_name, r->name());
6073 /* Add the final region */
6076 plist.add (ARDOUR::Properties::start, r->start() + pos);
6077 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6078 plist.add (ARDOUR::Properties::name, new_name);
6079 plist.add (ARDOUR::Properties::layer, 0);
6081 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6082 /* because we set annouce to false, manually add the new region to the
6085 RegionFactory::map_add (nr);
6086 pl->add_region (nr, r->position() + pos);
6089 new_regions.push_front(nr);
6094 /* We might have removed regions, which alters other regions' layering_index,
6095 so we need to do a recursive diff here.
6097 vector<Command*> cmds;
6099 _session->add_commands (cmds);
6101 _session->add_command (new StatefulDiffCommand (pl));
6105 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6106 set_selected_regionview_from_region_list ((*i), Selection::Add);
6112 Editor::place_transient()
6118 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6124 framepos_t where = get_preferred_edit_position();
6126 _session->begin_reversible_command (_("place transient"));
6128 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6129 framepos_t position = (*r)->region()->position();
6130 (*r)->region()->add_transient(where - position);
6133 _session->commit_reversible_command ();
6137 Editor::remove_transient(ArdourCanvas::Item* item)
6143 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6146 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6147 _arv->remove_transient (*(float*) _line->get_data ("position"));
6151 Editor::snap_regions_to_grid ()
6153 list <boost::shared_ptr<Playlist > > used_playlists;
6155 RegionSelection rs = get_regions_from_selection_and_entered ();
6157 if (!_session || rs.empty()) {
6161 _session->begin_reversible_command (_("snap regions to grid"));
6163 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6165 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6167 if (!pl->frozen()) {
6168 /* we haven't seen this playlist before */
6170 /* remember used playlists so we can thaw them later */
6171 used_playlists.push_back(pl);
6175 framepos_t start_frame = (*r)->region()->first_frame ();
6176 snap_to (start_frame);
6177 (*r)->region()->set_position (start_frame);
6180 while (used_playlists.size() > 0) {
6181 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6183 used_playlists.pop_front();
6186 _session->commit_reversible_command ();
6190 Editor::close_region_gaps ()
6192 list <boost::shared_ptr<Playlist > > used_playlists;
6194 RegionSelection rs = get_regions_from_selection_and_entered ();
6196 if (!_session || rs.empty()) {
6200 Dialog dialog (_("Close Region Gaps"));
6203 table.set_spacings (12);
6204 table.set_border_width (12);
6205 Label* l = manage (left_aligned_label (_("Crossfade length")));
6206 table.attach (*l, 0, 1, 0, 1);
6208 SpinButton spin_crossfade (1, 0);
6209 spin_crossfade.set_range (0, 15);
6210 spin_crossfade.set_increments (1, 1);
6211 spin_crossfade.set_value (5);
6212 table.attach (spin_crossfade, 1, 2, 0, 1);
6214 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6216 l = manage (left_aligned_label (_("Pull-back length")));
6217 table.attach (*l, 0, 1, 1, 2);
6219 SpinButton spin_pullback (1, 0);
6220 spin_pullback.set_range (0, 100);
6221 spin_pullback.set_increments (1, 1);
6222 spin_pullback.set_value(30);
6223 table.attach (spin_pullback, 1, 2, 1, 2);
6225 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6227 dialog.get_vbox()->pack_start (table);
6228 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6229 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6232 if (dialog.run () == RESPONSE_CANCEL) {
6236 framepos_t crossfade_len = spin_crossfade.get_value();
6237 framepos_t pull_back_frames = spin_pullback.get_value();
6239 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6240 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6242 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6244 _session->begin_reversible_command (_("close region gaps"));
6247 boost::shared_ptr<Region> last_region;
6249 rs.sort_by_position_and_track();
6251 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6253 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6255 if (!pl->frozen()) {
6256 /* we haven't seen this playlist before */
6258 /* remember used playlists so we can thaw them later */
6259 used_playlists.push_back(pl);
6263 framepos_t position = (*r)->region()->position();
6265 if (idx == 0 || position < last_region->position()){
6266 last_region = (*r)->region();
6271 (*r)->region()->trim_front( (position - pull_back_frames));
6272 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6274 last_region = (*r)->region();
6279 while (used_playlists.size() > 0) {
6280 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6282 used_playlists.pop_front();
6285 _session->commit_reversible_command ();
6289 Editor::tab_to_transient (bool forward)
6291 AnalysisFeatureList positions;
6293 RegionSelection rs = get_regions_from_selection_and_entered ();
6299 framepos_t pos = _session->audible_frame ();
6301 if (!selection->tracks.empty()) {
6303 /* don't waste time searching for transients in duplicate playlists.
6306 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6308 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6310 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6313 boost::shared_ptr<Track> tr = rtv->track();
6315 boost::shared_ptr<Playlist> pl = tr->playlist ();
6317 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6320 positions.push_back (result);
6333 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6334 (*r)->region()->get_transients (positions);
6338 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6341 AnalysisFeatureList::iterator x;
6343 for (x = positions.begin(); x != positions.end(); ++x) {
6349 if (x != positions.end ()) {
6350 _session->request_locate (*x);
6354 AnalysisFeatureList::reverse_iterator x;
6356 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6362 if (x != positions.rend ()) {
6363 _session->request_locate (*x);
6369 Editor::playhead_forward_to_grid ()
6375 framepos_t pos = playhead_cursor->current_frame ();
6376 if (pos < max_framepos - 1) {
6378 snap_to_internal (pos, 1, false);
6379 _session->request_locate (pos);
6385 Editor::playhead_backward_to_grid ()
6391 framepos_t pos = playhead_cursor->current_frame ();
6394 snap_to_internal (pos, -1, false);
6395 _session->request_locate (pos);
6400 Editor::set_track_height (Height h)
6402 TrackSelection& ts (selection->tracks);
6404 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6405 (*x)->set_height_enum (h);
6410 Editor::toggle_tracks_active ()
6412 TrackSelection& ts (selection->tracks);
6414 bool target = false;
6420 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6421 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6425 target = !rtv->_route->active();
6428 rtv->_route->set_active (target, this);
6434 Editor::remove_tracks ()
6436 TrackSelection& ts (selection->tracks);
6442 vector<string> choices;
6446 const char* trackstr;
6448 vector<boost::shared_ptr<Route> > routes;
6449 bool special_bus = false;
6451 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6452 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6454 if (rtv->is_track()) {
6460 routes.push_back (rtv->_route);
6462 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6467 if (special_bus && !Config->get_allow_special_bus_removal()) {
6468 MessageDialog msg (_("That would be bad news ...."),
6472 msg.set_secondary_text (string_compose (_(
6473 "Removing the master or monitor bus is such a bad idea\n\
6474 that %1 is not going to allow it.\n\
6476 If you really want to do this sort of thing\n\
6477 edit your ardour.rc file to set the\n\
6478 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6485 if (ntracks + nbusses == 0) {
6490 trackstr = _("tracks");
6492 trackstr = _("track");
6496 busstr = _("busses");
6503 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6504 "(You may also lose the playlists associated with the %2)\n\n"
6505 "This action cannot be undone, and the session file will be overwritten!"),
6506 ntracks, trackstr, nbusses, busstr);
6508 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6509 "(You may also lose the playlists associated with the %2)\n\n"
6510 "This action cannot be undone, and the session file will be overwritten!"),
6513 } else if (nbusses) {
6514 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6515 "This action cannot be undon, and the session file will be overwritten"),
6519 choices.push_back (_("No, do nothing."));
6520 if (ntracks + nbusses > 1) {
6521 choices.push_back (_("Yes, remove them."));
6523 choices.push_back (_("Yes, remove it."));
6528 title = string_compose (_("Remove %1"), trackstr);
6530 title = string_compose (_("Remove %1"), busstr);
6533 Choice prompter (title, prompt, choices);
6535 if (prompter.run () != 1) {
6539 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6540 _session->remove_route (*x);
6545 Editor::do_insert_time ()
6547 if (selection->tracks.empty()) {
6551 InsertTimeDialog d (*this);
6552 int response = d.run ();
6554 if (response != RESPONSE_OK) {
6558 if (d.distance() == 0) {
6562 InsertTimeOption opt = d.intersected_region_action ();
6565 get_preferred_edit_position(),
6571 d.move_glued_markers(),
6572 d.move_locked_markers(),
6578 Editor::insert_time (
6579 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6580 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6583 bool commit = false;
6585 if (Config->get_edit_mode() == Lock) {
6589 begin_reversible_command (_("insert time"));
6591 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6593 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6597 /* don't operate on any playlist more than once, which could
6598 * happen if "all playlists" is enabled, but there is more
6599 * than 1 track using playlists "from" a given track.
6602 set<boost::shared_ptr<Playlist> > pl;
6604 if (all_playlists) {
6605 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6607 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6608 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6613 if ((*x)->playlist ()) {
6614 pl.insert ((*x)->playlist ());
6618 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6620 (*i)->clear_changes ();
6621 (*i)->clear_owned_changes ();
6623 if (opt == SplitIntersected) {
6627 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6629 vector<Command*> cmds;
6631 _session->add_commands (cmds);
6633 _session->add_command (new StatefulDiffCommand (*i));
6638 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6640 rtav->route ()->shift (pos, frames);
6648 XMLNode& before (_session->locations()->get_state());
6649 Locations::LocationList copy (_session->locations()->list());
6651 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6653 Locations::LocationList::const_iterator tmp;
6655 bool const was_locked = (*i)->locked ();
6656 if (locked_markers_too) {
6660 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6662 if ((*i)->start() >= pos) {
6663 (*i)->set_start ((*i)->start() + frames);
6664 if (!(*i)->is_mark()) {
6665 (*i)->set_end ((*i)->end() + frames);
6678 XMLNode& after (_session->locations()->get_state());
6679 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6684 _session->tempo_map().insert_time (pos, frames);
6688 commit_reversible_command ();
6693 Editor::fit_selected_tracks ()
6695 if (!selection->tracks.empty()) {
6696 fit_tracks (selection->tracks);
6700 /* no selected tracks - use tracks with selected regions */
6702 if (!selection->regions.empty()) {
6703 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6704 tvl.push_back (&(*r)->get_time_axis_view ());
6710 } else if (internal_editing()) {
6711 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6714 if (entered_track) {
6715 tvl.push_back (entered_track);
6723 Editor::fit_tracks (TrackViewList & tracks)
6725 if (tracks.empty()) {
6729 uint32_t child_heights = 0;
6730 int visible_tracks = 0;
6732 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6734 if (!(*t)->marked_for_display()) {
6738 child_heights += (*t)->effective_height() - (*t)->current_height();
6742 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6743 double first_y_pos = DBL_MAX;
6745 if (h < TimeAxisView::preset_height (HeightSmall)) {
6746 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6747 /* too small to be displayed */
6751 undo_visual_stack.push_back (current_visual_state (true));
6752 no_save_visual = true;
6754 /* build a list of all tracks, including children */
6757 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6759 TimeAxisView::Children c = (*i)->get_child_list ();
6760 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6761 all.push_back (j->get());
6765 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6767 bool prev_was_selected = false;
6768 bool is_selected = tracks.contains (all.front());
6769 bool next_is_selected;
6771 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6773 TrackViewList::iterator next;
6778 if (next != all.end()) {
6779 next_is_selected = tracks.contains (*next);
6781 next_is_selected = false;
6784 if ((*t)->marked_for_display ()) {
6786 (*t)->set_height (h);
6787 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6789 if (prev_was_selected && next_is_selected) {
6790 hide_track_in_display (*t);
6795 prev_was_selected = is_selected;
6796 is_selected = next_is_selected;
6800 set the controls_layout height now, because waiting for its size
6801 request signal handler will cause the vertical adjustment setting to fail
6804 controls_layout.property_height () = _full_canvas_height;
6805 vertical_adjustment.set_value (first_y_pos);
6807 redo_visual_stack.push_back (current_visual_state (true));
6811 Editor::save_visual_state (uint32_t n)
6813 while (visual_states.size() <= n) {
6814 visual_states.push_back (0);
6817 if (visual_states[n] != 0) {
6818 delete visual_states[n];
6821 visual_states[n] = current_visual_state (true);
6826 Editor::goto_visual_state (uint32_t n)
6828 if (visual_states.size() <= n) {
6832 if (visual_states[n] == 0) {
6836 use_visual_state (*visual_states[n]);
6840 Editor::start_visual_state_op (uint32_t n)
6842 save_visual_state (n);
6844 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6846 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6847 pup->set_text (buf);
6852 Editor::cancel_visual_state_op (uint32_t n)
6854 goto_visual_state (n);
6858 Editor::toggle_region_mute ()
6860 if (_ignore_region_action) {
6864 RegionSelection rs = get_regions_from_selection_and_entered ();
6870 if (rs.size() > 1) {
6871 begin_reversible_command (_("mute regions"));
6873 begin_reversible_command (_("mute region"));
6876 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6878 (*i)->region()->playlist()->clear_changes ();
6879 (*i)->region()->set_muted (!(*i)->region()->muted ());
6880 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6884 commit_reversible_command ();
6888 Editor::combine_regions ()
6890 /* foreach track with selected regions, take all selected regions
6891 and join them into a new region containing the subregions (as a
6895 typedef set<RouteTimeAxisView*> RTVS;
6898 if (selection->regions.empty()) {
6902 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6903 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6906 tracks.insert (rtv);
6910 begin_reversible_command (_("combine regions"));
6912 vector<RegionView*> new_selection;
6914 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6917 if ((rv = (*i)->combine_regions ()) != 0) {
6918 new_selection.push_back (rv);
6922 selection->clear_regions ();
6923 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6924 selection->add (*i);
6927 commit_reversible_command ();
6931 Editor::uncombine_regions ()
6933 typedef set<RouteTimeAxisView*> RTVS;
6936 if (selection->regions.empty()) {
6940 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6941 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6944 tracks.insert (rtv);
6948 begin_reversible_command (_("uncombine regions"));
6950 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6951 (*i)->uncombine_regions ();
6954 commit_reversible_command ();
6958 Editor::toggle_midi_input_active (bool flip_others)
6961 boost::shared_ptr<RouteList> rl (new RouteList);
6963 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6964 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6970 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6973 rl->push_back (rtav->route());
6974 onoff = !mt->input_active();
6978 _session->set_exclusive_input_active (rl, onoff, flip_others);