2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
60 #include "ardour_ui.h"
63 #include "time_axis_view.h"
64 #include "route_time_axis.h"
65 #include "audio_time_axis.h"
66 #include "automation_time_axis.h"
67 #include "control_point.h"
68 #include "streamview.h"
69 #include "audio_streamview.h"
70 #include "audio_region_view.h"
71 #include "midi_region_view.h"
72 #include "rgb_macros.h"
73 #include "selection_templates.h"
74 #include "selection.h"
76 #include "gtk-custom-hruler.h"
77 #include "gui_thread.h"
80 #include "editor_drag.h"
81 #include "strip_silence_dialog.h"
82 #include "editor_routes.h"
83 #include "editor_regions.h"
84 #include "quantize_dialog.h"
85 #include "interthread_progress_window.h"
86 #include "insert_time_dialog.h"
87 #include "normalize_dialog.h"
88 #include "editor_cursors.h"
89 #include "mouse_cursors.h"
90 #include "patch_change_dialog.h"
91 #include "transpose_dialog.h"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
101 using Gtkmm2ext::Keyboard;
103 /***********************************************************************
105 ***********************************************************************/
108 Editor::undo (uint32_t n)
110 if (_drags->active ()) {
120 Editor::redo (uint32_t n)
122 if (_drags->active ()) {
132 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
136 list <boost::shared_ptr<Playlist > > used_playlists;
138 if (regions.empty()) {
142 begin_reversible_command (_("split"));
144 // if splitting a single region, and snap-to is using
145 // region boundaries, don't pay attention to them
147 if (regions.size() == 1) {
148 switch (_snap_type) {
149 case SnapToRegionStart:
150 case SnapToRegionSync:
151 case SnapToRegionEnd:
160 EditorFreeze(); /* Emit Signal */
163 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
165 RegionSelection::iterator tmp;
167 /* XXX this test needs to be more complicated, to make sure we really
168 have something to split.
171 if (!(*a)->region()->covers (where)) {
179 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
187 /* we haven't seen this playlist before */
189 /* remember used playlists so we can thaw them later */
190 used_playlists.push_back(pl);
195 pl->clear_changes ();
196 pl->split_region ((*a)->region(), where);
197 _session->add_command (new StatefulDiffCommand (pl));
203 while (used_playlists.size() > 0) {
204 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
206 used_playlists.pop_front();
209 commit_reversible_command ();
212 EditorThaw(); /* Emit Signal */
216 /** Move one extreme of the current range selection. If more than one range is selected,
217 * the start of the earliest range or the end of the latest range is moved.
219 * @param move_end true to move the end of the current range selection, false to move
221 * @param next true to move the extreme to the next region boundary, false to move to
225 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
227 if (selection->time.start() == selection->time.end_frame()) {
231 framepos_t start = selection->time.start ();
232 framepos_t end = selection->time.end_frame ();
234 /* the position of the thing we may move */
235 framepos_t pos = move_end ? end : start;
236 int dir = next ? 1 : -1;
238 /* so we don't find the current region again */
239 if (dir > 0 || pos > 0) {
243 framepos_t const target = get_region_boundary (pos, dir, true, false);
258 begin_reversible_command (_("alter selection"));
259 selection->set_preserving_all_ranges (start, end);
260 commit_reversible_command ();
264 Editor::nudge_forward_release (GdkEventButton* ev)
266 if (ev->state & Keyboard::PrimaryModifier) {
267 nudge_forward (false, true);
269 nudge_forward (false, false);
275 Editor::nudge_backward_release (GdkEventButton* ev)
277 if (ev->state & Keyboard::PrimaryModifier) {
278 nudge_backward (false, true);
280 nudge_backward (false, false);
287 Editor::nudge_forward (bool next, bool force_playhead)
290 framepos_t next_distance;
296 RegionSelection rs = get_regions_from_selection_and_entered ();
298 if (!force_playhead && !rs.empty()) {
300 begin_reversible_command (_("nudge regions forward"));
302 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
303 boost::shared_ptr<Region> r ((*i)->region());
305 distance = get_nudge_distance (r->position(), next_distance);
308 distance = next_distance;
312 r->set_position (r->position() + distance);
313 _session->add_command (new StatefulDiffCommand (r));
316 commit_reversible_command ();
319 } else if (!force_playhead && !selection->markers.empty()) {
323 begin_reversible_command (_("nudge location forward"));
325 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
327 Location* loc = find_location_from_marker ((*i), is_start);
331 XMLNode& before (loc->get_state());
334 distance = get_nudge_distance (loc->start(), next_distance);
336 distance = next_distance;
338 if (max_framepos - distance > loc->start() + loc->length()) {
339 loc->set_start (loc->start() + distance);
341 loc->set_start (max_framepos - loc->length());
344 distance = get_nudge_distance (loc->end(), next_distance);
346 distance = next_distance;
348 if (max_framepos - distance > loc->end()) {
349 loc->set_end (loc->end() + distance);
351 loc->set_end (max_framepos);
354 XMLNode& after (loc->get_state());
355 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
359 commit_reversible_command ();
362 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
363 _session->request_locate (playhead_cursor->current_frame () + distance);
368 Editor::nudge_backward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions backward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
394 if (r->position() > distance) {
395 r->set_position (r->position() - distance);
399 _session->add_command (new StatefulDiffCommand (r));
402 commit_reversible_command ();
404 } else if (!force_playhead && !selection->markers.empty()) {
408 begin_reversible_command (_("nudge location forward"));
410 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
412 Location* loc = find_location_from_marker ((*i), is_start);
416 XMLNode& before (loc->get_state());
419 distance = get_nudge_distance (loc->start(), next_distance);
421 distance = next_distance;
423 if (distance < loc->start()) {
424 loc->set_start (loc->start() - distance);
429 distance = get_nudge_distance (loc->end(), next_distance);
432 distance = next_distance;
435 if (distance < loc->end() - loc->length()) {
436 loc->set_end (loc->end() - distance);
438 loc->set_end (loc->length());
442 XMLNode& after (loc->get_state());
443 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
447 commit_reversible_command ();
451 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
453 if (playhead_cursor->current_frame () > distance) {
454 _session->request_locate (playhead_cursor->current_frame () - distance);
456 _session->goto_start();
462 Editor::nudge_forward_capture_offset ()
464 RegionSelection rs = get_regions_from_selection_and_entered ();
466 if (!_session || rs.empty()) {
470 begin_reversible_command (_("nudge forward"));
472 framepos_t const distance = _session->worst_output_latency();
474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
475 boost::shared_ptr<Region> r ((*i)->region());
478 r->set_position (r->position() + distance);
479 _session->add_command(new StatefulDiffCommand (r));
482 commit_reversible_command ();
486 Editor::nudge_backward_capture_offset ()
488 RegionSelection rs = get_regions_from_selection_and_entered ();
490 if (!_session || rs.empty()) {
494 begin_reversible_command (_("nudge backward"));
496 framepos_t const distance = _session->worst_output_latency();
498 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
499 boost::shared_ptr<Region> r ((*i)->region());
503 if (r->position() > distance) {
504 r->set_position (r->position() - distance);
508 _session->add_command(new StatefulDiffCommand (r));
511 commit_reversible_command ();
517 Editor::move_to_start ()
519 _session->goto_start ();
523 Editor::move_to_end ()
526 _session->request_locate (_session->current_end_frame());
530 Editor::build_region_boundary_cache ()
533 vector<RegionPoint> interesting_points;
534 boost::shared_ptr<Region> r;
535 TrackViewList tracks;
538 region_boundary_cache.clear ();
544 switch (_snap_type) {
545 case SnapToRegionStart:
546 interesting_points.push_back (Start);
548 case SnapToRegionEnd:
549 interesting_points.push_back (End);
551 case SnapToRegionSync:
552 interesting_points.push_back (SyncPoint);
554 case SnapToRegionBoundary:
555 interesting_points.push_back (Start);
556 interesting_points.push_back (End);
559 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
564 TimeAxisView *ontrack = 0;
567 if (!selection->tracks.empty()) {
568 tlist = selection->tracks.filter_to_unique_playlists ();
570 tlist = track_views.filter_to_unique_playlists ();
573 while (pos < _session->current_end_frame() && !at_end) {
576 framepos_t lpos = max_framepos;
578 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
580 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
581 if (*p == interesting_points.back()) {
584 /* move to next point type */
590 rpos = r->first_frame();
594 rpos = r->last_frame();
598 rpos = r->sync_position ();
606 RouteTimeAxisView *rtav;
608 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
609 if (rtav->track() != 0) {
610 speed = rtav->track()->speed();
614 rpos = track_frame_to_session_frame (rpos, speed);
620 /* prevent duplicates, but we don't use set<> because we want to be able
624 vector<framepos_t>::iterator ri;
626 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
632 if (ri == region_boundary_cache.end()) {
633 region_boundary_cache.push_back (rpos);
640 /* finally sort to be sure that the order is correct */
642 sort (region_boundary_cache.begin(), region_boundary_cache.end());
645 boost::shared_ptr<Region>
646 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
648 TrackViewList::iterator i;
649 framepos_t closest = max_framepos;
650 boost::shared_ptr<Region> ret;
654 framepos_t track_frame;
655 RouteTimeAxisView *rtav;
657 for (i = tracks.begin(); i != tracks.end(); ++i) {
660 boost::shared_ptr<Region> r;
663 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
664 if (rtav->track()!=0)
665 track_speed = rtav->track()->speed();
668 track_frame = session_frame_to_track_frame(frame, track_speed);
670 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
676 rpos = r->first_frame ();
680 rpos = r->last_frame ();
684 rpos = r->sync_position ();
688 // rpos is a "track frame", converting it to "_session frame"
689 rpos = track_frame_to_session_frame(rpos, track_speed);
692 distance = rpos - frame;
694 distance = frame - rpos;
697 if (distance < closest) {
709 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
711 framecnt_t distance = max_framepos;
712 framepos_t current_nearest = -1;
714 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
715 framepos_t contender;
718 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
724 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
728 d = ::llabs (pos - contender);
731 current_nearest = contender;
736 return current_nearest;
740 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
745 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
747 if (!selection->tracks.empty()) {
749 target = find_next_region_boundary (pos, dir, selection->tracks);
753 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
754 get_onscreen_tracks (tvl);
755 target = find_next_region_boundary (pos, dir, tvl);
757 target = find_next_region_boundary (pos, dir, track_views);
763 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
764 get_onscreen_tracks (tvl);
765 target = find_next_region_boundary (pos, dir, tvl);
767 target = find_next_region_boundary (pos, dir, track_views);
775 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
777 framepos_t pos = playhead_cursor->current_frame ();
784 // so we don't find the current region again..
785 if (dir > 0 || pos > 0) {
789 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
793 _session->request_locate (target);
797 Editor::cursor_to_next_region_boundary (bool with_selection)
799 cursor_to_region_boundary (with_selection, 1);
803 Editor::cursor_to_previous_region_boundary (bool with_selection)
805 cursor_to_region_boundary (with_selection, -1);
809 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
811 boost::shared_ptr<Region> r;
812 framepos_t pos = cursor->current_frame ();
818 TimeAxisView *ontrack = 0;
820 // so we don't find the current region again..
824 if (!selection->tracks.empty()) {
826 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
828 } else if (clicked_axisview) {
831 t.push_back (clicked_axisview);
833 r = find_next_region (pos, point, dir, t, &ontrack);
837 r = find_next_region (pos, point, dir, track_views, &ontrack);
846 pos = r->first_frame ();
850 pos = r->last_frame ();
854 pos = r->sync_position ();
859 RouteTimeAxisView *rtav;
861 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
862 if (rtav->track() != 0) {
863 speed = rtav->track()->speed();
867 pos = track_frame_to_session_frame(pos, speed);
869 if (cursor == playhead_cursor) {
870 _session->request_locate (pos);
872 cursor->set_position (pos);
877 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
879 cursor_to_region_point (cursor, point, 1);
883 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
885 cursor_to_region_point (cursor, point, -1);
889 Editor::cursor_to_selection_start (EditorCursor *cursor)
893 switch (mouse_mode) {
895 if (!selection->regions.empty()) {
896 pos = selection->regions.start();
901 if (!selection->time.empty()) {
902 pos = selection->time.start ();
910 if (cursor == playhead_cursor) {
911 _session->request_locate (pos);
913 cursor->set_position (pos);
918 Editor::cursor_to_selection_end (EditorCursor *cursor)
922 switch (mouse_mode) {
924 if (!selection->regions.empty()) {
925 pos = selection->regions.end_frame();
930 if (!selection->time.empty()) {
931 pos = selection->time.end_frame ();
939 if (cursor == playhead_cursor) {
940 _session->request_locate (pos);
942 cursor->set_position (pos);
947 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
957 if (selection->markers.empty()) {
961 if (!mouse_frame (mouse, ignored)) {
965 add_location_mark (mouse);
968 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
972 framepos_t pos = loc->start();
974 // so we don't find the current region again..
975 if (dir > 0 || pos > 0) {
979 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
983 loc->move_to (target);
987 Editor::selected_marker_to_next_region_boundary (bool with_selection)
989 selected_marker_to_region_boundary (with_selection, 1);
993 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
995 selected_marker_to_region_boundary (with_selection, -1);
999 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1001 boost::shared_ptr<Region> r;
1006 if (!_session || selection->markers.empty()) {
1010 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1014 TimeAxisView *ontrack = 0;
1018 // so we don't find the current region again..
1022 if (!selection->tracks.empty()) {
1024 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1028 r = find_next_region (pos, point, dir, track_views, &ontrack);
1037 pos = r->first_frame ();
1041 pos = r->last_frame ();
1045 pos = r->adjust_to_sync (r->first_frame());
1050 RouteTimeAxisView *rtav;
1052 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1053 if (rtav->track() != 0) {
1054 speed = rtav->track()->speed();
1058 pos = track_frame_to_session_frame(pos, speed);
1064 Editor::selected_marker_to_next_region_point (RegionPoint point)
1066 selected_marker_to_region_point (point, 1);
1070 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1072 selected_marker_to_region_point (point, -1);
1076 Editor::selected_marker_to_selection_start ()
1082 if (!_session || selection->markers.empty()) {
1086 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1090 switch (mouse_mode) {
1092 if (!selection->regions.empty()) {
1093 pos = selection->regions.start();
1098 if (!selection->time.empty()) {
1099 pos = selection->time.start ();
1111 Editor::selected_marker_to_selection_end ()
1117 if (!_session || selection->markers.empty()) {
1121 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1125 switch (mouse_mode) {
1127 if (!selection->regions.empty()) {
1128 pos = selection->regions.end_frame();
1133 if (!selection->time.empty()) {
1134 pos = selection->time.end_frame ();
1146 Editor::scroll_playhead (bool forward)
1148 framepos_t pos = playhead_cursor->current_frame ();
1149 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1152 if (pos == max_framepos) {
1156 if (pos < max_framepos - delta) {
1175 _session->request_locate (pos);
1179 Editor::cursor_align (bool playhead_to_edit)
1185 if (playhead_to_edit) {
1187 if (selection->markers.empty()) {
1191 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1194 /* move selected markers to playhead */
1196 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1199 Location* loc = find_location_from_marker (*i, ignored);
1201 if (loc->is_mark()) {
1202 loc->set_start (playhead_cursor->current_frame ());
1204 loc->set (playhead_cursor->current_frame (),
1205 playhead_cursor->current_frame () + loc->length());
1212 Editor::scroll_backward (float pages)
1214 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1215 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1218 if (leftmost_frame < cnt) {
1221 frame = leftmost_frame - cnt;
1224 reset_x_origin (frame);
1228 Editor::scroll_forward (float pages)
1230 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1231 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1234 if (max_framepos - cnt < leftmost_frame) {
1235 frame = max_framepos - cnt;
1237 frame = leftmost_frame + cnt;
1240 reset_x_origin (frame);
1244 Editor::scroll_tracks_down ()
1246 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1247 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1248 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1251 vertical_adjustment.set_value (vert_value);
1255 Editor::scroll_tracks_up ()
1257 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1261 Editor::scroll_tracks_down_line ()
1263 double vert_value = vertical_adjustment.get_value() + 60;
1265 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1266 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1269 vertical_adjustment.set_value (vert_value);
1273 Editor::scroll_tracks_up_line ()
1275 reset_y_origin (vertical_adjustment.get_value() - 60);
1281 Editor::tav_zoom_step (bool coarser)
1283 _routes->suspend_redisplay ();
1287 if (selection->tracks.empty()) {
1290 ts = &selection->tracks;
1293 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1294 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1295 tv->step_height (coarser);
1298 _routes->resume_redisplay ();
1302 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1304 _routes->suspend_redisplay ();
1308 if (selection->tracks.empty() || force_all) {
1311 ts = &selection->tracks;
1314 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1315 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1316 uint32_t h = tv->current_height ();
1321 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1326 tv->set_height (h + 5);
1330 _routes->resume_redisplay ();
1334 Editor::clamp_samples_per_pixel (double& fpp) const
1336 bool clamped = false;
1343 if (max_framepos / fpp < 800) {
1344 fpp = max_framepos / 800.0;
1352 Editor::temporal_zoom_step (bool coarser)
1354 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1356 double nfpp = samples_per_pixel;
1359 nfpp = min (9e6, nfpp * 1.61803399);
1361 nfpp = max (1.0, nfpp / 1.61803399);
1364 temporal_zoom (nfpp);
1368 Editor::temporal_zoom (double fpp)
1374 framepos_t current_page = current_page_samples();
1375 framepos_t current_leftmost = leftmost_frame;
1376 framepos_t current_rightmost;
1377 framepos_t current_center;
1378 framepos_t new_page_size;
1379 framepos_t half_page_size;
1380 framepos_t leftmost_after_zoom = 0;
1382 bool in_track_canvas;
1386 clamp_samples_per_pixel (fpp);
1387 if (fpp == samples_per_pixel) {
1393 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1394 // segfaults for lack of memory. If somebody decides this is not high enough I
1395 // believe it can be raisen to higher values but some limit must be in place.
1400 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1401 half_page_size = new_page_size / 2;
1403 switch (zoom_focus) {
1405 leftmost_after_zoom = current_leftmost;
1408 case ZoomFocusRight:
1409 current_rightmost = leftmost_frame + current_page;
1410 if (current_rightmost < new_page_size) {
1411 leftmost_after_zoom = 0;
1413 leftmost_after_zoom = current_rightmost - new_page_size;
1417 case ZoomFocusCenter:
1418 current_center = current_leftmost + (current_page/2);
1419 if (current_center < half_page_size) {
1420 leftmost_after_zoom = 0;
1422 leftmost_after_zoom = current_center - half_page_size;
1426 case ZoomFocusPlayhead:
1427 /* centre playhead */
1428 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1431 leftmost_after_zoom = 0;
1432 } else if (l > max_framepos) {
1433 leftmost_after_zoom = max_framepos - new_page_size;
1435 leftmost_after_zoom = (framepos_t) l;
1439 case ZoomFocusMouse:
1440 /* try to keep the mouse over the same point in the display */
1442 if (!mouse_frame (where, in_track_canvas)) {
1443 /* use playhead instead */
1444 where = playhead_cursor->current_frame ();
1446 if (where < half_page_size) {
1447 leftmost_after_zoom = 0;
1449 leftmost_after_zoom = where - half_page_size;
1454 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1457 leftmost_after_zoom = 0;
1458 } else if (l > max_framepos) {
1459 leftmost_after_zoom = max_framepos - new_page_size;
1461 leftmost_after_zoom = (framepos_t) l;
1468 /* try to keep the edit point in the same place */
1469 where = get_preferred_edit_position ();
1473 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1476 leftmost_after_zoom = 0;
1477 } else if (l > max_framepos) {
1478 leftmost_after_zoom = max_framepos - new_page_size;
1480 leftmost_after_zoom = (framepos_t) l;
1484 /* edit point not defined */
1491 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1493 reposition_and_zoom (leftmost_after_zoom, nfpp);
1497 Editor::temporal_zoom_region (bool both_axes)
1499 framepos_t start = max_framepos;
1501 set<TimeAxisView*> tracks;
1503 RegionSelection rs = get_regions_from_selection_and_entered ();
1509 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1511 if ((*i)->region()->position() < start) {
1512 start = (*i)->region()->position();
1515 if ((*i)->region()->last_frame() + 1 > end) {
1516 end = (*i)->region()->last_frame() + 1;
1519 tracks.insert (&((*i)->get_time_axis_view()));
1522 /* now comes an "interesting" hack ... make sure we leave a little space
1523 at each end of the editor so that the zoom doesn't fit the region
1524 precisely to the screen.
1527 GdkScreen* screen = gdk_screen_get_default ();
1528 gint pixwidth = gdk_screen_get_width (screen);
1529 gint mmwidth = gdk_screen_get_width_mm (screen);
1530 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1531 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1533 if ((start == 0 && end == 0) || end < start) {
1537 framepos_t range = end - start;
1538 double new_fpp = (double) range / (double) _visible_canvas_width;
1539 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1541 if (start > extra_samples) {
1542 start -= extra_samples;
1547 if (max_framepos - extra_samples > end) {
1548 end += extra_samples;
1553 /* if we're zooming on both axes we need to save track heights etc.
1556 undo_visual_stack.push_back (current_visual_state (both_axes));
1558 PBD::Unwinder<bool> nsv (no_save_visual, true);
1560 temporal_zoom_by_frame (start, end);
1563 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1565 /* set visible track heights appropriately */
1567 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1568 (*t)->set_height (per_track_height);
1571 /* hide irrelevant tracks */
1573 _routes->suspend_redisplay ();
1575 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1576 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1577 hide_track_in_display (*i);
1581 _routes->resume_redisplay ();
1583 vertical_adjustment.set_value (0.0);
1586 redo_visual_stack.push_back (current_visual_state (both_axes));
1590 Editor::zoom_to_region (bool both_axes)
1592 temporal_zoom_region (both_axes);
1596 Editor::temporal_zoom_selection ()
1598 if (!selection) return;
1600 if (selection->time.empty()) {
1604 framepos_t start = selection->time[clicked_selection].start;
1605 framepos_t end = selection->time[clicked_selection].end;
1607 temporal_zoom_by_frame (start, end);
1611 Editor::temporal_zoom_session ()
1613 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1616 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1617 double s = _session->current_start_frame() - l * 0.01;
1621 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1622 temporal_zoom_by_frame (framecnt_t (s), e);
1627 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1629 if (!_session) return;
1631 if ((start == 0 && end == 0) || end < start) {
1635 framepos_t range = end - start;
1637 double const new_fpp = (double) range / (double) _visible_canvas_width;
1639 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1640 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1641 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1643 if (new_leftmost > middle) {
1647 if (new_leftmost < 0) {
1651 reposition_and_zoom (new_leftmost, new_fpp);
1655 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1660 double range_before = frame - leftmost_frame;
1663 new_fpp = samples_per_pixel;
1666 new_fpp *= 1.61803399;
1667 range_before *= 1.61803399;
1669 new_fpp = max(1.0,(new_fpp/1.61803399));
1670 range_before /= 1.61803399;
1673 if (new_fpp == samples_per_pixel) {
1677 framepos_t new_leftmost = frame - (framepos_t)range_before;
1679 if (new_leftmost > frame) {
1683 if (new_leftmost < 0) {
1687 reposition_and_zoom (new_leftmost, new_fpp);
1692 Editor::choose_new_marker_name(string &name) {
1694 if (!Config->get_name_new_markers()) {
1695 /* don't prompt user for a new name */
1699 ArdourPrompter dialog (true);
1701 dialog.set_prompt (_("New Name:"));
1703 dialog.set_title (_("New Location Marker"));
1705 dialog.set_name ("MarkNameWindow");
1706 dialog.set_size_request (250, -1);
1707 dialog.set_position (Gtk::WIN_POS_MOUSE);
1709 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1710 dialog.set_initial_text (name);
1714 switch (dialog.run ()) {
1715 case RESPONSE_ACCEPT:
1721 dialog.get_result(name);
1728 Editor::add_location_from_selection ()
1732 if (selection->time.empty()) {
1736 if (_session == 0 || clicked_axisview == 0) {
1740 framepos_t start = selection->time[clicked_selection].start;
1741 framepos_t end = selection->time[clicked_selection].end;
1743 _session->locations()->next_available_name(rangename,"selection");
1744 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1746 _session->begin_reversible_command (_("add marker"));
1747 XMLNode &before = _session->locations()->get_state();
1748 _session->locations()->add (location, true);
1749 XMLNode &after = _session->locations()->get_state();
1750 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1751 _session->commit_reversible_command ();
1755 Editor::add_location_mark (framepos_t where)
1759 select_new_marker = true;
1761 _session->locations()->next_available_name(markername,"mark");
1762 if (!choose_new_marker_name(markername)) {
1765 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1766 _session->begin_reversible_command (_("add marker"));
1767 XMLNode &before = _session->locations()->get_state();
1768 _session->locations()->add (location, true);
1769 XMLNode &after = _session->locations()->get_state();
1770 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1771 _session->commit_reversible_command ();
1775 Editor::add_location_from_playhead_cursor ()
1777 add_location_mark (_session->audible_frame());
1780 /** Add a range marker around each selected region */
1782 Editor::add_locations_from_region ()
1784 RegionSelection rs = get_regions_from_selection_and_entered ();
1790 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1791 XMLNode &before = _session->locations()->get_state();
1793 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1795 boost::shared_ptr<Region> region = (*i)->region ();
1797 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1799 _session->locations()->add (location, true);
1802 XMLNode &after = _session->locations()->get_state();
1803 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1804 _session->commit_reversible_command ();
1807 /** Add a single range marker around all selected regions */
1809 Editor::add_location_from_region ()
1811 RegionSelection rs = get_regions_from_selection_and_entered ();
1817 _session->begin_reversible_command (_("add marker"));
1818 XMLNode &before = _session->locations()->get_state();
1822 if (rs.size() > 1) {
1823 _session->locations()->next_available_name(markername, "regions");
1825 RegionView* rv = *(rs.begin());
1826 boost::shared_ptr<Region> region = rv->region();
1827 markername = region->name();
1830 if (!choose_new_marker_name(markername)) {
1834 // single range spanning all selected
1835 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1836 _session->locations()->add (location, true);
1838 XMLNode &after = _session->locations()->get_state();
1839 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1840 _session->commit_reversible_command ();
1846 Editor::jump_forward_to_mark ()
1852 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
1858 _session->request_locate (pos, _session->transport_rolling());
1862 Editor::jump_backward_to_mark ()
1868 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
1874 _session->request_locate (pos, _session->transport_rolling());
1880 framepos_t const pos = _session->audible_frame ();
1883 _session->locations()->next_available_name (markername, "mark");
1885 if (!choose_new_marker_name (markername)) {
1889 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1893 Editor::clear_markers ()
1896 _session->begin_reversible_command (_("clear markers"));
1897 XMLNode &before = _session->locations()->get_state();
1898 _session->locations()->clear_markers ();
1899 XMLNode &after = _session->locations()->get_state();
1900 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1901 _session->commit_reversible_command ();
1906 Editor::clear_ranges ()
1909 _session->begin_reversible_command (_("clear ranges"));
1910 XMLNode &before = _session->locations()->get_state();
1912 Location * looploc = _session->locations()->auto_loop_location();
1913 Location * punchloc = _session->locations()->auto_punch_location();
1914 Location * sessionloc = _session->locations()->session_range_location();
1916 _session->locations()->clear_ranges ();
1918 if (looploc) _session->locations()->add (looploc);
1919 if (punchloc) _session->locations()->add (punchloc);
1920 if (sessionloc) _session->locations()->add (sessionloc);
1922 XMLNode &after = _session->locations()->get_state();
1923 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1924 _session->commit_reversible_command ();
1929 Editor::clear_locations ()
1931 _session->begin_reversible_command (_("clear locations"));
1932 XMLNode &before = _session->locations()->get_state();
1933 _session->locations()->clear ();
1934 XMLNode &after = _session->locations()->get_state();
1935 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1936 _session->commit_reversible_command ();
1937 _session->locations()->clear ();
1941 Editor::unhide_markers ()
1943 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1944 Location *l = (*i).first;
1945 if (l->is_hidden() && l->is_mark()) {
1946 l->set_hidden(false, this);
1952 Editor::unhide_ranges ()
1954 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1955 Location *l = (*i).first;
1956 if (l->is_hidden() && l->is_range_marker()) {
1957 l->set_hidden(false, this);
1962 /* INSERT/REPLACE */
1965 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1969 RouteTimeAxisView *rtv = 0;
1970 boost::shared_ptr<Playlist> playlist;
1973 event.type = GDK_BUTTON_RELEASE;
1977 where = window_event_frame (&event, &cx, &cy);
1979 if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) {
1980 /* clearly outside canvas area */
1984 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1985 if (tv.first == 0) {
1989 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1993 if ((playlist = rtv->playlist()) == 0) {
1999 begin_reversible_command (_("insert dragged region"));
2000 playlist->clear_changes ();
2001 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2002 _session->add_command(new StatefulDiffCommand (playlist));
2003 commit_reversible_command ();
2007 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2010 RouteTimeAxisView *dest_rtv = 0;
2011 RouteTimeAxisView *source_rtv = 0;
2014 event.type = GDK_BUTTON_RELEASE;
2018 window_event_frame (&event, &cx, &cy);
2020 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2021 if (tv.first == 0) {
2025 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2029 /* use this drag source to add underlay to a track. But we really don't care
2030 about the Route, only the view of the route, so find it first */
2031 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2032 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2036 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2037 dest_rtv->add_underlay(source_rtv->view());
2044 Editor::insert_region_list_selection (float times)
2046 RouteTimeAxisView *tv = 0;
2047 boost::shared_ptr<Playlist> playlist;
2049 if (clicked_routeview != 0) {
2050 tv = clicked_routeview;
2051 } else if (!selection->tracks.empty()) {
2052 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2055 } else if (entered_track != 0) {
2056 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2063 if ((playlist = tv->playlist()) == 0) {
2067 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2072 begin_reversible_command (_("insert region"));
2073 playlist->clear_changes ();
2074 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2075 _session->add_command(new StatefulDiffCommand (playlist));
2076 commit_reversible_command ();
2079 /* BUILT-IN EFFECTS */
2082 Editor::reverse_selection ()
2087 /* GAIN ENVELOPE EDITING */
2090 Editor::edit_envelope ()
2097 Editor::transition_to_rolling (bool fwd)
2103 if (_session->config.get_external_sync()) {
2104 switch (Config->get_sync_source()) {
2108 /* transport controlled by the master */
2113 if (_session->is_auditioning()) {
2114 _session->cancel_audition ();
2118 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2122 Editor::play_from_start ()
2124 _session->request_locate (_session->current_start_frame(), true);
2128 Editor::play_from_edit_point ()
2130 _session->request_locate (get_preferred_edit_position(), true);
2134 Editor::play_from_edit_point_and_return ()
2136 framepos_t start_frame;
2137 framepos_t return_frame;
2139 start_frame = get_preferred_edit_position (true);
2141 if (_session->transport_rolling()) {
2142 _session->request_locate (start_frame, false);
2146 /* don't reset the return frame if its already set */
2148 if ((return_frame = _session->requested_return_frame()) < 0) {
2149 return_frame = _session->audible_frame();
2152 if (start_frame >= 0) {
2153 _session->request_roll_at_and_return (start_frame, return_frame);
2158 Editor::play_selection ()
2160 if (selection->time.empty()) {
2164 _session->request_play_range (&selection->time, true);
2168 Editor::get_preroll ()
2170 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2175 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2177 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2180 location -= get_preroll();
2182 //don't try to locate before the beginning of time
2186 //if follow_playhead is on, keep the playhead on the screen
2187 if ( _follow_playhead )
2188 if ( location < leftmost_frame )
2189 location = leftmost_frame;
2191 _session->request_locate( location );
2195 Editor::play_with_preroll ()
2197 if (selection->time.empty()) {
2200 framepos_t preroll = get_preroll();
2202 framepos_t start = 0;
2203 if (selection->time[clicked_selection].start > preroll)
2204 start = selection->time[clicked_selection].start - preroll;
2206 framepos_t end = selection->time[clicked_selection].end + preroll;
2208 AudioRange ar (start, end, 0);
2209 list<AudioRange> lar;
2212 _session->request_play_range (&lar, true);
2217 Editor::play_location (Location& location)
2219 if (location.start() <= location.end()) {
2223 _session->request_bounded_roll (location.start(), location.end());
2227 Editor::loop_location (Location& location)
2229 if (location.start() <= location.end()) {
2235 if ((tll = transport_loop_location()) != 0) {
2236 tll->set (location.start(), location.end());
2238 // enable looping, reposition and start rolling
2239 _session->request_play_loop (true);
2240 _session->request_locate (tll->start(), true);
2245 Editor::do_layer_operation (LayerOperation op)
2247 if (selection->regions.empty ()) {
2251 bool const multiple = selection->regions.size() > 1;
2255 begin_reversible_command (_("raise regions"));
2257 begin_reversible_command (_("raise region"));
2263 begin_reversible_command (_("raise regions to top"));
2265 begin_reversible_command (_("raise region to top"));
2271 begin_reversible_command (_("lower regions"));
2273 begin_reversible_command (_("lower region"));
2279 begin_reversible_command (_("lower regions to bottom"));
2281 begin_reversible_command (_("lower region"));
2286 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2287 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2288 (*i)->clear_owned_changes ();
2291 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2292 boost::shared_ptr<Region> r = (*i)->region ();
2304 r->lower_to_bottom ();
2308 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2309 vector<Command*> cmds;
2311 _session->add_commands (cmds);
2314 commit_reversible_command ();
2318 Editor::raise_region ()
2320 do_layer_operation (Raise);
2324 Editor::raise_region_to_top ()
2326 do_layer_operation (RaiseToTop);
2330 Editor::lower_region ()
2332 do_layer_operation (Lower);
2336 Editor::lower_region_to_bottom ()
2338 do_layer_operation (LowerToBottom);
2341 /** Show the region editor for the selected regions */
2343 Editor::show_region_properties ()
2345 selection->foreach_regionview (&RegionView::show_region_editor);
2348 /** Show the midi list editor for the selected MIDI regions */
2350 Editor::show_midi_list_editor ()
2352 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2356 Editor::rename_region ()
2358 RegionSelection rs = get_regions_from_selection_and_entered ();
2364 ArdourDialog d (*this, _("Rename Region"), true, false);
2366 Label label (_("New name:"));
2369 hbox.set_spacing (6);
2370 hbox.pack_start (label, false, false);
2371 hbox.pack_start (entry, true, true);
2373 d.get_vbox()->set_border_width (12);
2374 d.get_vbox()->pack_start (hbox, false, false);
2376 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2377 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2379 d.set_size_request (300, -1);
2381 entry.set_text (rs.front()->region()->name());
2382 entry.select_region (0, -1);
2384 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2390 int const ret = d.run();
2394 if (ret != RESPONSE_OK) {
2398 std::string str = entry.get_text();
2399 strip_whitespace_edges (str);
2401 rs.front()->region()->set_name (str);
2402 _regions->redisplay ();
2407 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2409 if (_session->is_auditioning()) {
2410 _session->cancel_audition ();
2413 // note: some potential for creativity here, because region doesn't
2414 // have to belong to the playlist that Route is handling
2416 // bool was_soloed = route.soloed();
2418 route.set_solo (true, this);
2420 _session->request_bounded_roll (region->position(), region->position() + region->length());
2422 /* XXX how to unset the solo state ? */
2425 /** Start an audition of the first selected region */
2427 Editor::play_edit_range ()
2429 framepos_t start, end;
2431 if (get_edit_op_range (start, end)) {
2432 _session->request_bounded_roll (start, end);
2437 Editor::play_selected_region ()
2439 framepos_t start = max_framepos;
2442 RegionSelection rs = get_regions_from_selection_and_entered ();
2448 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2449 if ((*i)->region()->position() < start) {
2450 start = (*i)->region()->position();
2452 if ((*i)->region()->last_frame() + 1 > end) {
2453 end = (*i)->region()->last_frame() + 1;
2457 _session->request_bounded_roll (start, end);
2461 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2463 _session->audition_region (region);
2467 Editor::region_from_selection ()
2469 if (clicked_axisview == 0) {
2473 if (selection->time.empty()) {
2477 framepos_t start = selection->time[clicked_selection].start;
2478 framepos_t end = selection->time[clicked_selection].end;
2480 TrackViewList tracks = get_tracks_for_range_action ();
2482 framepos_t selection_cnt = end - start + 1;
2484 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2485 boost::shared_ptr<Region> current;
2486 boost::shared_ptr<Playlist> pl;
2487 framepos_t internal_start;
2490 if ((pl = (*i)->playlist()) == 0) {
2494 if ((current = pl->top_region_at (start)) == 0) {
2498 internal_start = start - current->position();
2499 RegionFactory::region_name (new_name, current->name(), true);
2503 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2504 plist.add (ARDOUR::Properties::length, selection_cnt);
2505 plist.add (ARDOUR::Properties::name, new_name);
2506 plist.add (ARDOUR::Properties::layer, 0);
2508 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2513 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2515 if (selection->time.empty() || selection->tracks.empty()) {
2519 framepos_t start = selection->time[clicked_selection].start;
2520 framepos_t end = selection->time[clicked_selection].end;
2522 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2523 sort_track_selection (ts);
2525 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2526 boost::shared_ptr<Region> current;
2527 boost::shared_ptr<Playlist> playlist;
2528 framepos_t internal_start;
2531 if ((playlist = (*i)->playlist()) == 0) {
2535 if ((current = playlist->top_region_at(start)) == 0) {
2539 internal_start = start - current->position();
2540 RegionFactory::region_name (new_name, current->name(), true);
2544 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2545 plist.add (ARDOUR::Properties::length, end - start + 1);
2546 plist.add (ARDOUR::Properties::name, new_name);
2548 new_regions.push_back (RegionFactory::create (current, plist));
2553 Editor::split_multichannel_region ()
2555 RegionSelection rs = get_regions_from_selection_and_entered ();
2561 vector< boost::shared_ptr<Region> > v;
2563 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2564 (*x)->region()->separate_by_channel (*_session, v);
2569 Editor::new_region_from_selection ()
2571 region_from_selection ();
2572 cancel_selection ();
2576 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2578 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2579 case Evoral::OverlapNone:
2587 * - selected tracks, or if there are none...
2588 * - tracks containing selected regions, or if there are none...
2593 Editor::get_tracks_for_range_action () const
2597 if (selection->tracks.empty()) {
2599 /* use tracks with selected regions */
2601 RegionSelection rs = selection->regions;
2603 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2604 TimeAxisView* tv = &(*i)->get_time_axis_view();
2606 if (!t.contains (tv)) {
2612 /* no regions and no tracks: use all tracks */
2618 t = selection->tracks;
2621 return t.filter_to_unique_playlists();
2625 Editor::separate_regions_between (const TimeSelection& ts)
2627 bool in_command = false;
2628 boost::shared_ptr<Playlist> playlist;
2629 RegionSelection new_selection;
2631 TrackViewList tmptracks = get_tracks_for_range_action ();
2632 sort_track_selection (tmptracks);
2634 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2636 RouteTimeAxisView* rtv;
2638 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2640 if (rtv->is_track()) {
2642 /* no edits to destructive tracks */
2644 if (rtv->track()->destructive()) {
2648 if ((playlist = rtv->playlist()) != 0) {
2650 playlist->clear_changes ();
2652 /* XXX need to consider musical time selections here at some point */
2654 double speed = rtv->track()->speed();
2657 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2659 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2660 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2662 latest_regionviews.clear ();
2664 playlist->partition ((framepos_t)((*t).start * speed),
2665 (framepos_t)((*t).end * speed), false);
2669 if (!latest_regionviews.empty()) {
2671 rtv->view()->foreach_regionview (sigc::bind (
2672 sigc::ptr_fun (add_if_covered),
2673 &(*t), &new_selection));
2676 begin_reversible_command (_("separate"));
2680 /* pick up changes to existing regions */
2682 vector<Command*> cmds;
2683 playlist->rdiff (cmds);
2684 _session->add_commands (cmds);
2686 /* pick up changes to the playlist itself (adds/removes)
2689 _session->add_command(new StatefulDiffCommand (playlist));
2698 selection->set (new_selection);
2699 set_mouse_mode (MouseObject);
2701 commit_reversible_command ();
2705 struct PlaylistState {
2706 boost::shared_ptr<Playlist> playlist;
2710 /** Take tracks from get_tracks_for_range_action and cut any regions
2711 * on those tracks so that the tracks are empty over the time
2715 Editor::separate_region_from_selection ()
2717 /* preferentially use *all* ranges in the time selection if we're in range mode
2718 to allow discontiguous operation, since get_edit_op_range() currently
2719 returns a single range.
2722 if (!selection->time.empty()) {
2724 separate_regions_between (selection->time);
2731 if (get_edit_op_range (start, end)) {
2733 AudioRange ar (start, end, 1);
2737 separate_regions_between (ts);
2743 Editor::separate_region_from_punch ()
2745 Location* loc = _session->locations()->auto_punch_location();
2747 separate_regions_using_location (*loc);
2752 Editor::separate_region_from_loop ()
2754 Location* loc = _session->locations()->auto_loop_location();
2756 separate_regions_using_location (*loc);
2761 Editor::separate_regions_using_location (Location& loc)
2763 if (loc.is_mark()) {
2767 AudioRange ar (loc.start(), loc.end(), 1);
2772 separate_regions_between (ts);
2775 /** Separate regions under the selected region */
2777 Editor::separate_under_selected_regions ()
2779 vector<PlaylistState> playlists;
2783 rs = get_regions_from_selection_and_entered();
2785 if (!_session || rs.empty()) {
2789 begin_reversible_command (_("separate region under"));
2791 list<boost::shared_ptr<Region> > regions_to_remove;
2793 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2794 // we can't just remove the region(s) in this loop because
2795 // this removes them from the RegionSelection, and they thus
2796 // disappear from underneath the iterator, and the ++i above
2797 // SEGVs in a puzzling fashion.
2799 // so, first iterate over the regions to be removed from rs and
2800 // add them to the regions_to_remove list, and then
2801 // iterate over the list to actually remove them.
2803 regions_to_remove.push_back ((*i)->region());
2806 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2808 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2811 // is this check necessary?
2815 vector<PlaylistState>::iterator i;
2817 //only take state if this is a new playlist.
2818 for (i = playlists.begin(); i != playlists.end(); ++i) {
2819 if ((*i).playlist == playlist) {
2824 if (i == playlists.end()) {
2826 PlaylistState before;
2827 before.playlist = playlist;
2828 before.before = &playlist->get_state();
2830 playlist->freeze ();
2831 playlists.push_back(before);
2834 //Partition on the region bounds
2835 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2837 //Re-add region that was just removed due to the partition operation
2838 playlist->add_region( (*rl), (*rl)->first_frame() );
2841 vector<PlaylistState>::iterator pl;
2843 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2844 (*pl).playlist->thaw ();
2845 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2848 commit_reversible_command ();
2852 Editor::crop_region_to_selection ()
2854 if (!selection->time.empty()) {
2856 crop_region_to (selection->time.start(), selection->time.end_frame());
2863 if (get_edit_op_range (start, end)) {
2864 crop_region_to (start, end);
2871 Editor::crop_region_to (framepos_t start, framepos_t end)
2873 vector<boost::shared_ptr<Playlist> > playlists;
2874 boost::shared_ptr<Playlist> playlist;
2877 if (selection->tracks.empty()) {
2878 ts = track_views.filter_to_unique_playlists();
2880 ts = selection->tracks.filter_to_unique_playlists ();
2883 sort_track_selection (ts);
2885 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2887 RouteTimeAxisView* rtv;
2889 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2891 boost::shared_ptr<Track> t = rtv->track();
2893 if (t != 0 && ! t->destructive()) {
2895 if ((playlist = rtv->playlist()) != 0) {
2896 playlists.push_back (playlist);
2902 if (playlists.empty()) {
2906 framepos_t the_start;
2910 begin_reversible_command (_("trim to selection"));
2912 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2914 boost::shared_ptr<Region> region;
2918 if ((region = (*i)->top_region_at(the_start)) == 0) {
2922 /* now adjust lengths to that we do the right thing
2923 if the selection extends beyond the region
2926 the_start = max (the_start, (framepos_t) region->position());
2927 if (max_framepos - the_start < region->length()) {
2928 the_end = the_start + region->length() - 1;
2930 the_end = max_framepos;
2932 the_end = min (end, the_end);
2933 cnt = the_end - the_start + 1;
2935 region->clear_changes ();
2936 region->trim_to (the_start, cnt);
2937 _session->add_command (new StatefulDiffCommand (region));
2940 commit_reversible_command ();
2944 Editor::region_fill_track ()
2946 RegionSelection rs = get_regions_from_selection_and_entered ();
2948 if (!_session || rs.empty()) {
2952 framepos_t const end = _session->current_end_frame ();
2954 begin_reversible_command (Operations::region_fill);
2956 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2958 boost::shared_ptr<Region> region ((*i)->region());
2960 boost::shared_ptr<Playlist> pl = region->playlist();
2962 if (end <= region->last_frame()) {
2966 double times = (double) (end - region->last_frame()) / (double) region->length();
2972 pl->clear_changes ();
2973 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2974 _session->add_command (new StatefulDiffCommand (pl));
2977 commit_reversible_command ();
2981 Editor::region_fill_selection ()
2983 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2987 if (selection->time.empty()) {
2991 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2996 framepos_t start = selection->time[clicked_selection].start;
2997 framepos_t end = selection->time[clicked_selection].end;
2999 boost::shared_ptr<Playlist> playlist;
3001 if (selection->tracks.empty()) {
3005 framepos_t selection_length = end - start;
3006 float times = (float)selection_length / region->length();
3008 begin_reversible_command (Operations::fill_selection);
3010 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3012 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3014 if ((playlist = (*i)->playlist()) == 0) {
3018 playlist->clear_changes ();
3019 playlist->add_region (RegionFactory::create (region, true), start, times);
3020 _session->add_command (new StatefulDiffCommand (playlist));
3023 commit_reversible_command ();
3027 Editor::set_region_sync_position ()
3029 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3033 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3035 bool in_command = false;
3037 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3039 if (!(*r)->region()->covers (where)) {
3043 boost::shared_ptr<Region> region ((*r)->region());
3046 begin_reversible_command (_("set sync point"));
3050 region->clear_changes ();
3051 region->set_sync_position (where);
3052 _session->add_command(new StatefulDiffCommand (region));
3056 commit_reversible_command ();
3060 /** Remove the sync positions of the selection */
3062 Editor::remove_region_sync ()
3064 RegionSelection rs = get_regions_from_selection_and_entered ();
3070 begin_reversible_command (_("remove region sync"));
3072 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3074 (*i)->region()->clear_changes ();
3075 (*i)->region()->clear_sync_position ();
3076 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3079 commit_reversible_command ();
3083 Editor::naturalize_region ()
3085 RegionSelection rs = get_regions_from_selection_and_entered ();
3091 if (rs.size() > 1) {
3092 begin_reversible_command (_("move regions to original position"));
3094 begin_reversible_command (_("move region to original position"));
3097 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3098 (*i)->region()->clear_changes ();
3099 (*i)->region()->move_to_natural_position ();
3100 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3103 commit_reversible_command ();
3107 Editor::align_regions (RegionPoint what)
3109 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3115 begin_reversible_command (_("align selection"));
3117 framepos_t const position = get_preferred_edit_position ();
3119 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3120 align_region_internal ((*i)->region(), what, position);
3123 commit_reversible_command ();
3126 struct RegionSortByTime {
3127 bool operator() (const RegionView* a, const RegionView* b) {
3128 return a->region()->position() < b->region()->position();
3133 Editor::align_regions_relative (RegionPoint point)
3135 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3141 framepos_t const position = get_preferred_edit_position ();
3143 framepos_t distance = 0;
3147 list<RegionView*> sorted;
3148 rs.by_position (sorted);
3150 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3155 if (position > r->position()) {
3156 distance = position - r->position();
3158 distance = r->position() - position;
3164 if (position > r->last_frame()) {
3165 distance = position - r->last_frame();
3166 pos = r->position() + distance;
3168 distance = r->last_frame() - position;
3169 pos = r->position() - distance;
3175 pos = r->adjust_to_sync (position);
3176 if (pos > r->position()) {
3177 distance = pos - r->position();
3179 distance = r->position() - pos;
3185 if (pos == r->position()) {
3189 begin_reversible_command (_("align selection (relative)"));
3191 /* move first one specially */
3193 r->clear_changes ();
3194 r->set_position (pos);
3195 _session->add_command(new StatefulDiffCommand (r));
3197 /* move rest by the same amount */
3201 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3203 boost::shared_ptr<Region> region ((*i)->region());
3205 region->clear_changes ();
3208 region->set_position (region->position() + distance);
3210 region->set_position (region->position() - distance);
3213 _session->add_command(new StatefulDiffCommand (region));
3217 commit_reversible_command ();
3221 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3223 begin_reversible_command (_("align region"));
3224 align_region_internal (region, point, position);
3225 commit_reversible_command ();
3229 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3231 region->clear_changes ();
3235 region->set_position (region->adjust_to_sync (position));
3239 if (position > region->length()) {
3240 region->set_position (position - region->length());
3245 region->set_position (position);
3249 _session->add_command(new StatefulDiffCommand (region));
3253 Editor::trim_region_front ()
3259 Editor::trim_region_back ()
3261 trim_region (false);
3265 Editor::trim_region (bool front)
3267 framepos_t where = get_preferred_edit_position();
3268 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3274 begin_reversible_command (front ? _("trim front") : _("trim back"));
3276 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3277 if (!(*i)->region()->locked()) {
3279 (*i)->region()->clear_changes ();
3282 (*i)->region()->trim_front (where);
3283 maybe_locate_with_edit_preroll ( where );
3285 (*i)->region()->trim_end (where);
3286 maybe_locate_with_edit_preroll ( where );
3289 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3293 commit_reversible_command ();
3296 /** Trim the end of the selected regions to the position of the edit cursor */
3298 Editor::trim_region_to_loop ()
3300 Location* loc = _session->locations()->auto_loop_location();
3304 trim_region_to_location (*loc, _("trim to loop"));
3308 Editor::trim_region_to_punch ()
3310 Location* loc = _session->locations()->auto_punch_location();
3314 trim_region_to_location (*loc, _("trim to punch"));
3318 Editor::trim_region_to_location (const Location& loc, const char* str)
3320 RegionSelection rs = get_regions_from_selection_and_entered ();
3322 begin_reversible_command (str);
3324 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3325 RegionView* rv = (*x);
3327 /* require region to span proposed trim */
3328 switch (rv->region()->coverage (loc.start(), loc.end())) {
3329 case Evoral::OverlapInternal:
3335 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3344 if (tav->track() != 0) {
3345 speed = tav->track()->speed();
3348 start = session_frame_to_track_frame (loc.start(), speed);
3349 end = session_frame_to_track_frame (loc.end(), speed);
3351 rv->region()->clear_changes ();
3352 rv->region()->trim_to (start, (end - start));
3353 _session->add_command(new StatefulDiffCommand (rv->region()));
3356 commit_reversible_command ();
3360 Editor::trim_region_to_previous_region_end ()
3362 return trim_to_region(false);
3366 Editor::trim_region_to_next_region_start ()
3368 return trim_to_region(true);
3372 Editor::trim_to_region(bool forward)
3374 RegionSelection rs = get_regions_from_selection_and_entered ();
3376 begin_reversible_command (_("trim to region"));
3378 boost::shared_ptr<Region> next_region;
3380 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3382 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3388 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3396 if (atav->track() != 0) {
3397 speed = atav->track()->speed();
3401 boost::shared_ptr<Region> region = arv->region();
3402 boost::shared_ptr<Playlist> playlist (region->playlist());
3404 region->clear_changes ();
3408 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3414 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3415 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3419 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3425 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3427 arv->region_changed (ARDOUR::bounds_change);
3430 _session->add_command(new StatefulDiffCommand (region));
3433 commit_reversible_command ();
3437 Editor::unfreeze_route ()
3439 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3443 clicked_routeview->track()->unfreeze ();
3447 Editor::_freeze_thread (void* arg)
3449 return static_cast<Editor*>(arg)->freeze_thread ();
3453 Editor::freeze_thread ()
3455 /* create event pool because we may need to talk to the session */
3456 SessionEvent::create_per_thread_pool ("freeze events", 64);
3457 /* create per-thread buffers for process() tree to use */
3458 current_interthread_info->process_thread.get_buffers ();
3459 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3460 current_interthread_info->done = true;
3461 current_interthread_info->process_thread.drop_buffers();
3466 Editor::freeze_route ()
3472 /* stop transport before we start. this is important */
3474 _session->request_transport_speed (0.0);
3476 /* wait for just a little while, because the above call is asynchronous */
3480 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3484 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3486 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3487 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3489 d.set_title (_("Cannot freeze"));
3494 if (clicked_routeview->track()->has_external_redirects()) {
3495 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"
3496 "Freezing will only process the signal as far as the first send/insert/return."),
3497 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3499 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3500 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3501 d.set_title (_("Freeze Limits"));
3503 int response = d.run ();
3506 case Gtk::RESPONSE_CANCEL:
3513 InterThreadInfo itt;
3514 current_interthread_info = &itt;
3516 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3518 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3520 set_canvas_cursor (_cursors->wait);
3522 while (!itt.done && !itt.cancel) {
3523 gtk_main_iteration ();
3526 current_interthread_info = 0;
3527 set_canvas_cursor (current_canvas_cursor);
3531 Editor::bounce_range_selection (bool replace, bool enable_processing)
3533 if (selection->time.empty()) {
3537 TrackSelection views = selection->tracks;
3539 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3541 if (enable_processing) {
3543 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3545 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3547 _("You can't perform this operation because the processing of the signal "
3548 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3549 "You can do this without processing, which is a different operation.")
3551 d.set_title (_("Cannot bounce"));
3558 framepos_t start = selection->time[clicked_selection].start;
3559 framepos_t end = selection->time[clicked_selection].end;
3560 framepos_t cnt = end - start + 1;
3562 begin_reversible_command (_("bounce range"));
3564 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3566 RouteTimeAxisView* rtv;
3568 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3572 boost::shared_ptr<Playlist> playlist;
3574 if ((playlist = rtv->playlist()) == 0) {
3578 InterThreadInfo itt;
3580 playlist->clear_changes ();
3581 playlist->clear_owned_changes ();
3583 boost::shared_ptr<Region> r;
3585 if (enable_processing) {
3586 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3588 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3596 list<AudioRange> ranges;
3597 ranges.push_back (AudioRange (start, start+cnt, 0));
3598 playlist->cut (ranges); // discard result
3599 playlist->add_region (r, start);
3602 vector<Command*> cmds;
3603 playlist->rdiff (cmds);
3604 _session->add_commands (cmds);
3606 _session->add_command (new StatefulDiffCommand (playlist));
3609 commit_reversible_command ();
3612 /** Delete selected regions, automation points or a time range */
3619 /** Cut selected regions, automation points or a time range */
3626 /** Copy selected regions, automation points or a time range */
3634 /** @return true if a Cut, Copy or Clear is possible */
3636 Editor::can_cut_copy () const
3638 switch (effective_mouse_mode()) {
3641 if (!selection->regions.empty() || !selection->points.empty()) {
3647 if (!selection->time.empty()) {
3660 /** Cut, copy or clear selected regions, automation points or a time range.
3661 * @param op Operation (Cut, Copy or Clear)
3664 Editor::cut_copy (CutCopyOp op)
3666 /* only cancel selection if cut/copy is successful.*/
3672 opname = _("delete");
3681 opname = _("clear");
3685 /* if we're deleting something, and the mouse is still pressed,
3686 the thing we started a drag for will be gone when we release
3687 the mouse button(s). avoid this. see part 2 at the end of
3691 if (op == Delete || op == Cut || op == Clear) {
3692 if (_drags->active ()) {
3697 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3698 cut_buffer->clear ();
3700 if (entered_marker) {
3702 /* cut/delete op while pointing at a marker */
3705 Location* loc = find_location_from_marker (entered_marker, ignored);
3707 if (_session && loc) {
3708 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3715 if (internal_editing()) {
3717 switch (effective_mouse_mode()) {
3730 /* we only want to cut regions if some are selected */
3732 if (!selection->regions.empty()) {
3733 rs = selection->regions;
3736 switch (effective_mouse_mode()) {
3739 //find regions's gain line
3740 AudioRegionView *rview = dynamic_cast<AudioRegionView*>(clicked_regionview);
3741 AutomationTimeAxisView *tview = dynamic_cast<AutomationTimeAxisView*>(clicked_trackview);
3743 AudioRegionGainLine *line = rview->get_gain_line();
3746 //cut region gain points in the selection
3747 AutomationList& alist (line->the_list());
3748 XMLNode &before = alist.get_state();
3749 AutomationList* what_we_got = 0;
3750 if ((what_we_got = alist.cut (selection->time.front().start - rview->audio_region()->position(), selection->time.front().end - rview->audio_region()->position())) != 0) {
3751 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3756 rview->set_envelope_visible(true);
3757 rview->audio_region()->set_envelope_active(true);
3760 AutomationLine *line = *(tview->lines.begin());
3763 //cut auto points in the selection
3764 AutomationList& alist (line->the_list());
3765 XMLNode &before = alist.get_state();
3766 AutomationList* what_we_got = 0;
3767 if ((what_we_got = alist.cut (selection->time.front().start, selection->time.front().end)) != 0) {
3768 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3778 if (!rs.empty() || !selection->points.empty()) {
3779 begin_reversible_command (opname + _(" objects"));
3782 cut_copy_regions (op, rs);
3784 if (op == Cut || op == Delete) {
3785 selection->clear_regions ();
3789 if (!selection->points.empty()) {
3790 cut_copy_points (op);
3792 if (op == Cut || op == Delete) {
3793 selection->clear_points ();
3797 commit_reversible_command ();
3801 if (selection->time.empty()) {
3802 framepos_t start, end;
3803 if (!get_edit_op_range (start, end)) {
3806 selection->set (start, end);
3809 begin_reversible_command (opname + _(" range"));
3810 cut_copy_ranges (op);
3811 commit_reversible_command ();
3813 if (op == Cut || op == Delete) {
3814 selection->clear_time ();
3824 if (op == Delete || op == Cut || op == Clear) {
3829 struct AutomationRecord {
3830 AutomationRecord () : state (0) {}
3831 AutomationRecord (XMLNode* s) : state (s) {}
3833 XMLNode* state; ///< state before any operation
3834 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3837 /** Cut, copy or clear selected automation points.
3838 * @param op Operation (Cut, Copy or Clear)
3841 Editor::cut_copy_points (CutCopyOp op)
3843 if (selection->points.empty ()) {
3847 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3848 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3850 /* Keep a record of the AutomationLists that we end up using in this operation */
3851 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3854 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3855 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3856 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3857 if (lists.find (al) == lists.end ()) {
3858 /* We haven't seen this list yet, so make a record for it. This includes
3859 taking a copy of its current state, in case this is needed for undo later.
3861 lists[al] = AutomationRecord (&al->get_state ());
3865 if (op == Cut || op == Copy) {
3866 /* This operation will involve putting things in the cut buffer, so create an empty
3867 ControlList for each of our source lists to put the cut buffer data in.
3869 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3870 i->second.copy = i->first->create (i->first->parameter ());
3873 /* Add all selected points to the relevant copy ControlLists */
3874 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3875 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3876 AutomationList::const_iterator j = (*i)->model ();
3877 lists[al].copy->add ((*j)->when, (*j)->value);
3880 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3881 /* Correct this copy list so that it starts at time 0 */
3882 double const start = i->second.copy->front()->when;
3883 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3884 (*j)->when -= start;
3887 /* And add it to the cut buffer */
3888 cut_buffer->add (i->second.copy);
3892 if (op == Delete || op == Cut) {
3893 /* This operation needs to remove things from the main AutomationList, so do that now */
3895 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3896 i->first->freeze ();
3899 /* Remove each selected point from its AutomationList */
3900 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3901 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3902 al->erase ((*i)->model ());
3905 /* Thaw the lists and add undo records for them */
3906 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3907 boost::shared_ptr<AutomationList> al = i->first;
3909 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3914 /** Cut, copy or clear selected automation points.
3915 * @param op Operation (Cut, Copy or Clear)
3918 Editor::cut_copy_midi (CutCopyOp op)
3920 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3921 MidiRegionView* mrv = *i;
3922 mrv->cut_copy_clear (op);
3928 struct lt_playlist {
3929 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3930 return a.playlist < b.playlist;
3934 struct PlaylistMapping {
3936 boost::shared_ptr<Playlist> pl;
3938 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3941 /** Remove `clicked_regionview' */
3943 Editor::remove_clicked_region ()
3945 if (clicked_routeview == 0 || clicked_regionview == 0) {
3949 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3951 begin_reversible_command (_("remove region"));
3952 playlist->clear_changes ();
3953 playlist->clear_owned_changes ();
3954 playlist->remove_region (clicked_regionview->region());
3956 /* We might have removed regions, which alters other regions' layering_index,
3957 so we need to do a recursive diff here.
3959 vector<Command*> cmds;
3960 playlist->rdiff (cmds);
3961 _session->add_commands (cmds);
3963 _session->add_command(new StatefulDiffCommand (playlist));
3964 commit_reversible_command ();
3968 /** Remove the selected regions */
3970 Editor::remove_selected_regions ()
3972 RegionSelection rs = get_regions_from_selection_and_entered ();
3974 if (!_session || rs.empty()) {
3978 begin_reversible_command (_("remove region"));
3980 list<boost::shared_ptr<Region> > regions_to_remove;
3982 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3983 // we can't just remove the region(s) in this loop because
3984 // this removes them from the RegionSelection, and they thus
3985 // disappear from underneath the iterator, and the ++i above
3986 // SEGVs in a puzzling fashion.
3988 // so, first iterate over the regions to be removed from rs and
3989 // add them to the regions_to_remove list, and then
3990 // iterate over the list to actually remove them.
3992 regions_to_remove.push_back ((*i)->region());
3995 vector<boost::shared_ptr<Playlist> > playlists;
3997 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3999 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4002 // is this check necessary?
4006 /* get_regions_from_selection_and_entered() guarantees that
4007 the playlists involved are unique, so there is no need
4011 playlists.push_back (playlist);
4013 playlist->clear_changes ();
4014 playlist->clear_owned_changes ();
4015 playlist->freeze ();
4016 playlist->remove_region (*rl);
4019 vector<boost::shared_ptr<Playlist> >::iterator pl;
4021 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4024 /* We might have removed regions, which alters other regions' layering_index,
4025 so we need to do a recursive diff here.
4027 vector<Command*> cmds;
4028 (*pl)->rdiff (cmds);
4029 _session->add_commands (cmds);
4031 _session->add_command(new StatefulDiffCommand (*pl));
4034 commit_reversible_command ();
4037 /** Cut, copy or clear selected regions.
4038 * @param op Operation (Cut, Copy or Clear)
4041 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4043 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4044 a map when we want ordered access to both elements. i think.
4047 vector<PlaylistMapping> pmap;
4049 framepos_t first_position = max_framepos;
4051 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4052 FreezeList freezelist;
4054 /* get ordering correct before we cut/copy */
4056 rs.sort_by_position_and_track ();
4058 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4060 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4062 if (op == Cut || op == Clear || op == Delete) {
4063 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4066 FreezeList::iterator fl;
4068 // only take state if this is a new playlist.
4069 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4075 if (fl == freezelist.end()) {
4076 pl->clear_changes();
4077 pl->clear_owned_changes ();
4079 freezelist.insert (pl);
4084 TimeAxisView* tv = &(*x)->get_time_axis_view();
4085 vector<PlaylistMapping>::iterator z;
4087 for (z = pmap.begin(); z != pmap.end(); ++z) {
4088 if ((*z).tv == tv) {
4093 if (z == pmap.end()) {
4094 pmap.push_back (PlaylistMapping (tv));
4098 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4100 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4103 /* region not yet associated with a playlist (e.g. unfinished
4110 TimeAxisView& tv = (*x)->get_time_axis_view();
4111 boost::shared_ptr<Playlist> npl;
4112 RegionSelection::iterator tmp;
4119 vector<PlaylistMapping>::iterator z;
4121 for (z = pmap.begin(); z != pmap.end(); ++z) {
4122 if ((*z).tv == &tv) {
4127 assert (z != pmap.end());
4130 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4138 boost::shared_ptr<Region> r = (*x)->region();
4139 boost::shared_ptr<Region> _xx;
4145 pl->remove_region (r);
4149 _xx = RegionFactory::create (r);
4150 npl->add_region (_xx, r->position() - first_position);
4151 pl->remove_region (r);
4155 /* copy region before adding, so we're not putting same object into two different playlists */
4156 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4160 pl->remove_region (r);
4169 list<boost::shared_ptr<Playlist> > foo;
4171 /* the pmap is in the same order as the tracks in which selected regions occured */
4173 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4176 foo.push_back ((*i).pl);
4181 cut_buffer->set (foo);
4185 _last_cut_copy_source_track = 0;
4187 _last_cut_copy_source_track = pmap.front().tv;
4191 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4194 /* We might have removed regions, which alters other regions' layering_index,
4195 so we need to do a recursive diff here.
4197 vector<Command*> cmds;
4198 (*pl)->rdiff (cmds);
4199 _session->add_commands (cmds);
4201 _session->add_command (new StatefulDiffCommand (*pl));
4206 Editor::cut_copy_ranges (CutCopyOp op)
4208 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4210 /* Sort the track selection now, so that it if is used, the playlists
4211 selected by the calls below to cut_copy_clear are in the order that
4212 their tracks appear in the editor. This makes things like paste
4213 of ranges work properly.
4216 sort_track_selection (ts);
4219 if (!entered_track) {
4222 ts.push_back (entered_track);
4225 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4226 (*i)->cut_copy_clear (*selection, op);
4231 Editor::paste (float times, bool from_context)
4233 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4235 paste_internal (get_preferred_edit_position (false, from_context), times);
4239 Editor::mouse_paste ()
4244 if (!mouse_frame (where, ignored)) {
4249 paste_internal (where, 1);
4253 Editor::paste_internal (framepos_t position, float times)
4255 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4257 if (internal_editing()) {
4258 if (cut_buffer->midi_notes.empty()) {
4262 if (cut_buffer->empty()) {
4267 if (position == max_framepos) {
4268 position = get_preferred_edit_position();
4269 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4273 TrackViewList::iterator i;
4276 /* get everything in the correct order */
4278 if (_edit_point == Editing::EditAtMouse && entered_track) {
4279 /* With the mouse edit point, paste onto the track under the mouse */
4280 ts.push_back (entered_track);
4281 } else if (!selection->tracks.empty()) {
4282 /* Otherwise, if there are some selected tracks, paste to them */
4283 ts = selection->tracks.filter_to_unique_playlists ();
4284 sort_track_selection (ts);
4285 } else if (_last_cut_copy_source_track) {
4286 /* Otherwise paste to the track that the cut/copy came from;
4287 see discussion in mantis #3333.
4289 ts.push_back (_last_cut_copy_source_track);
4292 if (internal_editing ()) {
4294 /* undo/redo is handled by individual tracks/regions */
4296 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4299 RegionSelection::iterator r;
4300 MidiNoteSelection::iterator cb;
4302 get_regions_at (rs, position, ts);
4304 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4305 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4306 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4308 mrv->paste (position, times, **cb);
4316 /* we do redo (do you do voodoo?) */
4318 begin_reversible_command (Operations::paste);
4320 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4321 (*i)->paste (position, times, *cut_buffer, nth);
4324 commit_reversible_command ();
4329 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4331 boost::shared_ptr<Playlist> playlist;
4332 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4333 RegionSelection foo;
4335 framepos_t const start_frame = regions.start ();
4336 framepos_t const end_frame = regions.end_frame ();
4338 begin_reversible_command (Operations::duplicate_region);
4340 selection->clear_regions ();
4342 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4344 boost::shared_ptr<Region> r ((*i)->region());
4346 TimeAxisView& tv = (*i)->get_time_axis_view();
4347 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4348 latest_regionviews.clear ();
4349 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4351 playlist = (*i)->region()->playlist();
4352 playlist->clear_changes ();
4353 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4354 _session->add_command(new StatefulDiffCommand (playlist));
4358 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4361 commit_reversible_command ();
4364 selection->set (foo);
4369 Editor::duplicate_selection (float times)
4371 if (selection->time.empty() || selection->tracks.empty()) {
4375 boost::shared_ptr<Playlist> playlist;
4376 vector<boost::shared_ptr<Region> > new_regions;
4377 vector<boost::shared_ptr<Region> >::iterator ri;
4379 create_region_from_selection (new_regions);
4381 if (new_regions.empty()) {
4385 begin_reversible_command (_("duplicate selection"));
4387 ri = new_regions.begin();
4389 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4391 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4392 if ((playlist = (*i)->playlist()) == 0) {
4395 playlist->clear_changes ();
4396 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4397 _session->add_command (new StatefulDiffCommand (playlist));
4400 if (ri == new_regions.end()) {
4405 commit_reversible_command ();
4408 /** Reset all selected points to the relevant default value */
4410 Editor::reset_point_selection ()
4412 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4413 ARDOUR::AutomationList::iterator j = (*i)->model ();
4414 (*j)->value = (*i)->line().the_list()->default_value ();
4419 Editor::center_playhead ()
4421 float const page = _visible_canvas_width * samples_per_pixel;
4422 center_screen_internal (playhead_cursor->current_frame (), page);
4426 Editor::center_edit_point ()
4428 float const page = _visible_canvas_width * samples_per_pixel;
4429 center_screen_internal (get_preferred_edit_position(), page);
4432 /** Caller must begin and commit a reversible command */
4434 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4436 playlist->clear_changes ();
4438 _session->add_command (new StatefulDiffCommand (playlist));
4442 Editor::nudge_track (bool use_edit, bool forwards)
4444 boost::shared_ptr<Playlist> playlist;
4445 framepos_t distance;
4446 framepos_t next_distance;
4450 start = get_preferred_edit_position();
4455 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4459 if (selection->tracks.empty()) {
4463 begin_reversible_command (_("nudge track"));
4465 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4467 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4469 if ((playlist = (*i)->playlist()) == 0) {
4473 playlist->clear_changes ();
4474 playlist->clear_owned_changes ();
4476 playlist->nudge_after (start, distance, forwards);
4478 vector<Command*> cmds;
4480 playlist->rdiff (cmds);
4481 _session->add_commands (cmds);
4483 _session->add_command (new StatefulDiffCommand (playlist));
4486 commit_reversible_command ();
4490 Editor::remove_last_capture ()
4492 vector<string> choices;
4499 if (Config->get_verify_remove_last_capture()) {
4500 prompt = _("Do you really want to destroy the last capture?"
4501 "\n(This is destructive and cannot be undone)");
4503 choices.push_back (_("No, do nothing."));
4504 choices.push_back (_("Yes, destroy it."));
4506 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4508 if (prompter.run () == 1) {
4509 _session->remove_last_capture ();
4510 _regions->redisplay ();
4514 _session->remove_last_capture();
4515 _regions->redisplay ();
4520 Editor::normalize_region ()
4526 RegionSelection rs = get_regions_from_selection_and_entered ();
4532 NormalizeDialog dialog (rs.size() > 1);
4534 if (dialog.run () == RESPONSE_CANCEL) {
4538 set_canvas_cursor (_cursors->wait);
4541 /* XXX: should really only count audio regions here */
4542 int const regions = rs.size ();
4544 /* Make a list of the selected audio regions' maximum amplitudes, and also
4545 obtain the maximum amplitude of them all.
4547 list<double> max_amps;
4549 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4550 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4552 dialog.descend (1.0 / regions);
4553 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4556 /* the user cancelled the operation */
4557 set_canvas_cursor (current_canvas_cursor);
4561 max_amps.push_back (a);
4562 max_amp = max (max_amp, a);
4567 begin_reversible_command (_("normalize"));
4569 list<double>::const_iterator a = max_amps.begin ();
4571 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4572 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4577 arv->region()->clear_changes ();
4579 double const amp = dialog.normalize_individually() ? *a : max_amp;
4581 arv->audio_region()->normalize (amp, dialog.target ());
4582 _session->add_command (new StatefulDiffCommand (arv->region()));
4587 commit_reversible_command ();
4588 set_canvas_cursor (current_canvas_cursor);
4593 Editor::reset_region_scale_amplitude ()
4599 RegionSelection rs = get_regions_from_selection_and_entered ();
4605 begin_reversible_command ("reset gain");
4607 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4608 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4611 arv->region()->clear_changes ();
4612 arv->audio_region()->set_scale_amplitude (1.0f);
4613 _session->add_command (new StatefulDiffCommand (arv->region()));
4616 commit_reversible_command ();
4620 Editor::adjust_region_gain (bool up)
4622 RegionSelection rs = get_regions_from_selection_and_entered ();
4624 if (!_session || rs.empty()) {
4628 begin_reversible_command ("adjust region gain");
4630 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4631 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4636 arv->region()->clear_changes ();
4638 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4646 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4647 _session->add_command (new StatefulDiffCommand (arv->region()));
4650 commit_reversible_command ();
4655 Editor::reverse_region ()
4661 Reverse rev (*_session);
4662 apply_filter (rev, _("reverse regions"));
4666 Editor::strip_region_silence ()
4672 RegionSelection rs = get_regions_from_selection_and_entered ();
4678 std::list<RegionView*> audio_only;
4680 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4681 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4683 audio_only.push_back (arv);
4687 StripSilenceDialog d (_session, audio_only);
4688 int const r = d.run ();
4692 if (r == Gtk::RESPONSE_OK) {
4693 ARDOUR::AudioIntervalMap silences;
4694 d.silences (silences);
4695 StripSilence s (*_session, silences, d.fade_length());
4696 apply_filter (s, _("strip silence"), &d);
4701 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4703 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4704 mrv.selection_as_notelist (selected, true);
4706 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4707 v.push_back (selected);
4709 framepos_t pos_frames = mrv.midi_region()->position();
4710 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4712 return op (mrv.midi_region()->model(), pos_beats, v);
4716 Editor::apply_midi_note_edit_op (MidiOperator& op)
4720 RegionSelection rs = get_regions_from_selection_and_entered ();
4726 begin_reversible_command (op.name ());
4728 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4729 RegionSelection::iterator tmp = r;
4732 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4735 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4738 _session->add_command (cmd);
4745 commit_reversible_command ();
4749 Editor::fork_region ()
4751 RegionSelection rs = get_regions_from_selection_and_entered ();
4757 begin_reversible_command (_("Fork Region(s)"));
4759 set_canvas_cursor (_cursors->wait);
4762 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4763 RegionSelection::iterator tmp = r;
4766 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4769 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4770 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4772 playlist->clear_changes ();
4773 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4774 _session->add_command(new StatefulDiffCommand (playlist));
4780 commit_reversible_command ();
4782 set_canvas_cursor (current_canvas_cursor);
4786 Editor::quantize_region ()
4788 int selected_midi_region_cnt = 0;
4794 RegionSelection rs = get_regions_from_selection_and_entered ();
4800 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4801 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4803 selected_midi_region_cnt++;
4807 if (selected_midi_region_cnt == 0) {
4811 QuantizeDialog* qd = new QuantizeDialog (*this);
4814 const int r = qd->run ();
4817 if (r == Gtk::RESPONSE_OK) {
4818 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4819 qd->start_grid_size(), qd->end_grid_size(),
4820 qd->strength(), qd->swing(), qd->threshold());
4822 apply_midi_note_edit_op (quant);
4827 Editor::insert_patch_change (bool from_context)
4829 RegionSelection rs = get_regions_from_selection_and_entered ();
4835 const framepos_t p = get_preferred_edit_position (false, from_context);
4837 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4838 there may be more than one, but the PatchChangeDialog can only offer
4839 one set of patch menus.
4841 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4843 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4844 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4846 if (d.run() == RESPONSE_CANCEL) {
4850 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4851 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4853 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4854 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4861 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4863 RegionSelection rs = get_regions_from_selection_and_entered ();
4869 begin_reversible_command (command);
4871 set_canvas_cursor (_cursors->wait);
4875 int const N = rs.size ();
4877 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4878 RegionSelection::iterator tmp = r;
4881 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4883 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4886 progress->descend (1.0 / N);
4889 if (arv->audio_region()->apply (filter, progress) == 0) {
4891 playlist->clear_changes ();
4892 playlist->clear_owned_changes ();
4894 if (filter.results.empty ()) {
4896 /* no regions returned; remove the old one */
4897 playlist->remove_region (arv->region ());
4901 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4903 /* first region replaces the old one */
4904 playlist->replace_region (arv->region(), *res, (*res)->position());
4908 while (res != filter.results.end()) {
4909 playlist->add_region (*res, (*res)->position());
4915 /* We might have removed regions, which alters other regions' layering_index,
4916 so we need to do a recursive diff here.
4918 vector<Command*> cmds;
4919 playlist->rdiff (cmds);
4920 _session->add_commands (cmds);
4922 _session->add_command(new StatefulDiffCommand (playlist));
4928 progress->ascend ();
4936 commit_reversible_command ();
4939 set_canvas_cursor (current_canvas_cursor);
4943 Editor::external_edit_region ()
4949 Editor::reset_region_gain_envelopes ()
4951 RegionSelection rs = get_regions_from_selection_and_entered ();
4953 if (!_session || rs.empty()) {
4957 _session->begin_reversible_command (_("reset region gain"));
4959 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4960 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4962 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4963 XMLNode& before (alist->get_state());
4965 arv->audio_region()->set_default_envelope ();
4966 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4970 _session->commit_reversible_command ();
4974 Editor::set_region_gain_visibility (RegionView* rv)
4976 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4978 arv->update_envelope_visibility();
4983 Editor::set_gain_envelope_visibility ()
4989 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4990 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4992 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
4998 Editor::toggle_gain_envelope_active ()
5000 if (_ignore_region_action) {
5004 RegionSelection rs = get_regions_from_selection_and_entered ();
5006 if (!_session || rs.empty()) {
5010 _session->begin_reversible_command (_("region gain envelope active"));
5012 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5013 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5015 arv->region()->clear_changes ();
5016 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5017 _session->add_command (new StatefulDiffCommand (arv->region()));
5021 _session->commit_reversible_command ();
5025 Editor::toggle_region_lock ()
5027 if (_ignore_region_action) {
5031 RegionSelection rs = get_regions_from_selection_and_entered ();
5033 if (!_session || rs.empty()) {
5037 _session->begin_reversible_command (_("toggle region lock"));
5039 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5040 (*i)->region()->clear_changes ();
5041 (*i)->region()->set_locked (!(*i)->region()->locked());
5042 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5045 _session->commit_reversible_command ();
5049 Editor::toggle_region_video_lock ()
5051 if (_ignore_region_action) {
5055 RegionSelection rs = get_regions_from_selection_and_entered ();
5057 if (!_session || rs.empty()) {
5061 _session->begin_reversible_command (_("Toggle Video Lock"));
5063 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5064 (*i)->region()->clear_changes ();
5065 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5066 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5069 _session->commit_reversible_command ();
5073 Editor::toggle_region_lock_style ()
5075 if (_ignore_region_action) {
5079 RegionSelection rs = get_regions_from_selection_and_entered ();
5081 if (!_session || rs.empty()) {
5085 _session->begin_reversible_command (_("region lock style"));
5087 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5088 (*i)->region()->clear_changes ();
5089 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5090 (*i)->region()->set_position_lock_style (ns);
5091 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5094 _session->commit_reversible_command ();
5098 Editor::toggle_opaque_region ()
5100 if (_ignore_region_action) {
5104 RegionSelection rs = get_regions_from_selection_and_entered ();
5106 if (!_session || rs.empty()) {
5110 _session->begin_reversible_command (_("change region opacity"));
5112 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5113 (*i)->region()->clear_changes ();
5114 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5115 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5118 _session->commit_reversible_command ();
5122 Editor::toggle_record_enable ()
5124 bool new_state = false;
5126 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5127 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5130 if (!rtav->is_track())
5134 new_state = !rtav->track()->record_enabled();
5138 rtav->track()->set_record_enabled (new_state, this);
5143 Editor::toggle_solo ()
5145 bool new_state = false;
5147 boost::shared_ptr<RouteList> rl (new RouteList);
5149 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5150 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5157 new_state = !rtav->route()->soloed ();
5161 rl->push_back (rtav->route());
5164 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5168 Editor::toggle_mute ()
5170 bool new_state = false;
5172 boost::shared_ptr<RouteList> rl (new RouteList);
5174 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5175 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5182 new_state = !rtav->route()->muted();
5186 rl->push_back (rtav->route());
5189 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5193 Editor::toggle_solo_isolate ()
5198 Editor::set_fade_length (bool in)
5200 RegionSelection rs = get_regions_from_selection_and_entered ();
5206 /* we need a region to measure the offset from the start */
5208 RegionView* rv = rs.front ();
5210 framepos_t pos = get_preferred_edit_position();
5214 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5215 /* edit point is outside the relevant region */
5220 if (pos <= rv->region()->position()) {
5224 len = pos - rv->region()->position();
5225 cmd = _("set fade in length");
5227 if (pos >= rv->region()->last_frame()) {
5231 len = rv->region()->last_frame() - pos;
5232 cmd = _("set fade out length");
5235 begin_reversible_command (cmd);
5237 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5238 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5244 boost::shared_ptr<AutomationList> alist;
5246 alist = tmp->audio_region()->fade_in();
5248 alist = tmp->audio_region()->fade_out();
5251 XMLNode &before = alist->get_state();
5254 tmp->audio_region()->set_fade_in_length (len);
5255 tmp->audio_region()->set_fade_in_active (true);
5257 tmp->audio_region()->set_fade_out_length (len);
5258 tmp->audio_region()->set_fade_out_active (true);
5261 XMLNode &after = alist->get_state();
5262 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5265 commit_reversible_command ();
5269 Editor::set_fade_in_shape (FadeShape shape)
5271 RegionSelection rs = get_regions_from_selection_and_entered ();
5277 begin_reversible_command (_("set fade in shape"));
5279 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5280 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5286 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5287 XMLNode &before = alist->get_state();
5289 tmp->audio_region()->set_fade_in_shape (shape);
5291 XMLNode &after = alist->get_state();
5292 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5295 commit_reversible_command ();
5300 Editor::set_fade_out_shape (FadeShape shape)
5302 RegionSelection rs = get_regions_from_selection_and_entered ();
5308 begin_reversible_command (_("set fade out shape"));
5310 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5311 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5317 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5318 XMLNode &before = alist->get_state();
5320 tmp->audio_region()->set_fade_out_shape (shape);
5322 XMLNode &after = alist->get_state();
5323 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5326 commit_reversible_command ();
5330 Editor::set_fade_in_active (bool yn)
5332 RegionSelection rs = get_regions_from_selection_and_entered ();
5338 begin_reversible_command (_("set fade in active"));
5340 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5341 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5348 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5350 ar->clear_changes ();
5351 ar->set_fade_in_active (yn);
5352 _session->add_command (new StatefulDiffCommand (ar));
5355 commit_reversible_command ();
5359 Editor::set_fade_out_active (bool yn)
5361 RegionSelection rs = get_regions_from_selection_and_entered ();
5367 begin_reversible_command (_("set fade out active"));
5369 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5370 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5376 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5378 ar->clear_changes ();
5379 ar->set_fade_out_active (yn);
5380 _session->add_command(new StatefulDiffCommand (ar));
5383 commit_reversible_command ();
5387 Editor::toggle_region_fades (int dir)
5389 if (_ignore_region_action) {
5393 boost::shared_ptr<AudioRegion> ar;
5396 RegionSelection rs = get_regions_from_selection_and_entered ();
5402 RegionSelection::iterator i;
5403 for (i = rs.begin(); i != rs.end(); ++i) {
5404 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5406 yn = ar->fade_out_active ();
5408 yn = ar->fade_in_active ();
5414 if (i == rs.end()) {
5418 /* XXX should this undo-able? */
5420 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5421 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5424 if (dir == 1 || dir == 0) {
5425 ar->set_fade_in_active (!yn);
5428 if (dir == -1 || dir == 0) {
5429 ar->set_fade_out_active (!yn);
5435 /** Update region fade visibility after its configuration has been changed */
5437 Editor::update_region_fade_visibility ()
5439 bool _fade_visibility = _session->config.get_show_region_fades ();
5441 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5442 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5444 if (_fade_visibility) {
5445 v->audio_view()->show_all_fades ();
5447 v->audio_view()->hide_all_fades ();
5454 Editor::set_edit_point ()
5459 if (!mouse_frame (where, ignored)) {
5465 if (selection->markers.empty()) {
5467 mouse_add_new_marker (where);
5472 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5475 loc->move_to (where);
5481 Editor::set_playhead_cursor ()
5483 if (entered_marker) {
5484 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5489 if (!mouse_frame (where, ignored)) {
5496 _session->request_locate (where, _session->transport_rolling());
5500 if ( Config->get_always_play_range() )
5501 cancel_time_selection();
5505 Editor::split_region ()
5507 if ( !selection->time.empty()) {
5508 separate_regions_between (selection->time);
5512 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5514 framepos_t where = get_preferred_edit_position ();
5520 split_regions_at (where, rs);
5523 struct EditorOrderRouteSorter {
5524 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5525 return a->order_key (EditorSort) < b->order_key (EditorSort);
5530 Editor::select_next_route()
5532 if (selection->tracks.empty()) {
5533 selection->set (track_views.front());
5537 TimeAxisView* current = selection->tracks.front();
5541 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5542 if (*i == current) {
5544 if (i != track_views.end()) {
5547 current = (*(track_views.begin()));
5548 //selection->set (*(track_views.begin()));
5553 rui = dynamic_cast<RouteUI *>(current);
5554 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5556 selection->set(current);
5558 ensure_track_visible(current);
5562 Editor::select_prev_route()
5564 if (selection->tracks.empty()) {
5565 selection->set (track_views.front());
5569 TimeAxisView* current = selection->tracks.front();
5573 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5574 if (*i == current) {
5576 if (i != track_views.rend()) {
5579 current = *(track_views.rbegin());
5584 rui = dynamic_cast<RouteUI *>(current);
5585 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5587 selection->set (current);
5589 ensure_track_visible(current);
5593 Editor::ensure_track_visible(TimeAxisView *track)
5595 if (track->hidden())
5598 double const current_view_min_y = vertical_adjustment.get_value();
5599 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5601 double const track_min_y = track->y_position ();
5602 double const track_max_y = track->y_position () + track->effective_height ();
5604 if (track_min_y >= current_view_min_y &&
5605 track_max_y <= current_view_max_y) {
5611 if (track_min_y < current_view_min_y) {
5612 // Track is above the current view
5613 new_value = track_min_y;
5615 // Track is below the current view
5616 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5619 vertical_adjustment.set_value(new_value);
5623 Editor::set_loop_from_selection (bool play)
5625 if (_session == 0 || selection->time.empty()) {
5629 framepos_t start = selection->time[clicked_selection].start;
5630 framepos_t end = selection->time[clicked_selection].end;
5632 set_loop_range (start, end, _("set loop range from selection"));
5635 _session->request_play_loop (true);
5636 _session->request_locate (start, true);
5641 Editor::set_loop_from_edit_range (bool play)
5643 if (_session == 0) {
5650 if (!get_edit_op_range (start, end)) {
5654 set_loop_range (start, end, _("set loop range from edit range"));
5657 _session->request_play_loop (true);
5658 _session->request_locate (start, true);
5663 Editor::set_loop_from_region (bool play)
5665 framepos_t start = max_framepos;
5668 RegionSelection rs = get_regions_from_selection_and_entered ();
5674 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5675 if ((*i)->region()->position() < start) {
5676 start = (*i)->region()->position();
5678 if ((*i)->region()->last_frame() + 1 > end) {
5679 end = (*i)->region()->last_frame() + 1;
5683 set_loop_range (start, end, _("set loop range from region"));
5686 _session->request_play_loop (true);
5687 _session->request_locate (start, true);
5692 Editor::set_punch_from_selection ()
5694 if (_session == 0 || selection->time.empty()) {
5698 framepos_t start = selection->time[clicked_selection].start;
5699 framepos_t end = selection->time[clicked_selection].end;
5701 set_punch_range (start, end, _("set punch range from selection"));
5705 Editor::set_punch_from_edit_range ()
5707 if (_session == 0) {
5714 if (!get_edit_op_range (start, end)) {
5718 set_punch_range (start, end, _("set punch range from edit range"));
5722 Editor::set_punch_from_region ()
5724 framepos_t start = max_framepos;
5727 RegionSelection rs = get_regions_from_selection_and_entered ();
5733 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5734 if ((*i)->region()->position() < start) {
5735 start = (*i)->region()->position();
5737 if ((*i)->region()->last_frame() + 1 > end) {
5738 end = (*i)->region()->last_frame() + 1;
5742 set_punch_range (start, end, _("set punch range from region"));
5746 Editor::pitch_shift_region ()
5748 RegionSelection rs = get_regions_from_selection_and_entered ();
5750 RegionSelection audio_rs;
5751 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5752 if (dynamic_cast<AudioRegionView*> (*i)) {
5753 audio_rs.push_back (*i);
5757 if (audio_rs.empty()) {
5761 pitch_shift (audio_rs, 1.2);
5765 Editor::transpose_region ()
5767 RegionSelection rs = get_regions_from_selection_and_entered ();
5769 list<MidiRegionView*> midi_region_views;
5770 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5771 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5773 midi_region_views.push_back (mrv);
5778 int const r = d.run ();
5779 if (r != RESPONSE_ACCEPT) {
5783 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5784 (*i)->midi_region()->transpose (d.semitones ());
5789 Editor::set_tempo_from_region ()
5791 RegionSelection rs = get_regions_from_selection_and_entered ();
5793 if (!_session || rs.empty()) {
5797 RegionView* rv = rs.front();
5799 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5803 Editor::use_range_as_bar ()
5805 framepos_t start, end;
5806 if (get_edit_op_range (start, end)) {
5807 define_one_bar (start, end);
5812 Editor::define_one_bar (framepos_t start, framepos_t end)
5814 framepos_t length = end - start;
5816 const Meter& m (_session->tempo_map().meter_at (start));
5818 /* length = 1 bar */
5820 /* now we want frames per beat.
5821 we have frames per bar, and beats per bar, so ...
5824 /* XXXX METER MATH */
5826 double frames_per_beat = length / m.divisions_per_bar();
5828 /* beats per minute = */
5830 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5832 /* now decide whether to:
5834 (a) set global tempo
5835 (b) add a new tempo marker
5839 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5841 bool do_global = false;
5843 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5845 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5846 at the start, or create a new marker
5849 vector<string> options;
5850 options.push_back (_("Cancel"));
5851 options.push_back (_("Add new marker"));
5852 options.push_back (_("Set global tempo"));
5855 _("Define one bar"),
5856 _("Do you want to set the global tempo or add a new tempo marker?"),
5860 c.set_default_response (2);
5876 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5877 if the marker is at the region starter, change it, otherwise add
5882 begin_reversible_command (_("set tempo from region"));
5883 XMLNode& before (_session->tempo_map().get_state());
5886 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5887 } else if (t.frame() == start) {
5888 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5890 Timecode::BBT_Time bbt;
5891 _session->tempo_map().bbt_time (start, bbt);
5892 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5895 XMLNode& after (_session->tempo_map().get_state());
5897 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5898 commit_reversible_command ();
5902 Editor::split_region_at_transients ()
5904 AnalysisFeatureList positions;
5906 RegionSelection rs = get_regions_from_selection_and_entered ();
5908 if (!_session || rs.empty()) {
5912 _session->begin_reversible_command (_("split regions"));
5914 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5916 RegionSelection::iterator tmp;
5921 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5923 if (ar && (ar->get_transients (positions) == 0)) {
5924 split_region_at_points ((*i)->region(), positions, true);
5931 _session->commit_reversible_command ();
5936 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5938 bool use_rhythmic_rodent = false;
5940 boost::shared_ptr<Playlist> pl = r->playlist();
5942 list<boost::shared_ptr<Region> > new_regions;
5948 if (positions.empty()) {
5953 if (positions.size() > 20 && can_ferret) {
5954 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);
5955 MessageDialog msg (msgstr,
5958 Gtk::BUTTONS_OK_CANCEL);
5961 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5962 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5964 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5967 msg.set_title (_("Excessive split?"));
5970 int response = msg.run();
5976 case RESPONSE_APPLY:
5977 use_rhythmic_rodent = true;
5984 if (use_rhythmic_rodent) {
5985 show_rhythm_ferret ();
5989 AnalysisFeatureList::const_iterator x;
5991 pl->clear_changes ();
5992 pl->clear_owned_changes ();
5994 x = positions.begin();
5996 if (x == positions.end()) {
6001 pl->remove_region (r);
6005 while (x != positions.end()) {
6007 /* deal with positons that are out of scope of present region bounds */
6008 if (*x <= 0 || *x > r->length()) {
6013 /* file start = original start + how far we from the initial position ?
6016 framepos_t file_start = r->start() + pos;
6018 /* length = next position - current position
6021 framepos_t len = (*x) - pos;
6023 /* XXX we do we really want to allow even single-sample regions?
6024 shouldn't we have some kind of lower limit on region size?
6033 if (RegionFactory::region_name (new_name, r->name())) {
6037 /* do NOT announce new regions 1 by one, just wait till they are all done */
6041 plist.add (ARDOUR::Properties::start, file_start);
6042 plist.add (ARDOUR::Properties::length, len);
6043 plist.add (ARDOUR::Properties::name, new_name);
6044 plist.add (ARDOUR::Properties::layer, 0);
6046 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6047 /* because we set annouce to false, manually add the new region to the
6050 RegionFactory::map_add (nr);
6052 pl->add_region (nr, r->position() + pos);
6055 new_regions.push_front(nr);
6064 RegionFactory::region_name (new_name, r->name());
6066 /* Add the final region */
6069 plist.add (ARDOUR::Properties::start, r->start() + pos);
6070 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6071 plist.add (ARDOUR::Properties::name, new_name);
6072 plist.add (ARDOUR::Properties::layer, 0);
6074 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6075 /* because we set annouce to false, manually add the new region to the
6078 RegionFactory::map_add (nr);
6079 pl->add_region (nr, r->position() + pos);
6082 new_regions.push_front(nr);
6087 /* We might have removed regions, which alters other regions' layering_index,
6088 so we need to do a recursive diff here.
6090 vector<Command*> cmds;
6092 _session->add_commands (cmds);
6094 _session->add_command (new StatefulDiffCommand (pl));
6098 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6099 set_selected_regionview_from_region_list ((*i), Selection::Add);
6105 Editor::place_transient()
6111 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6117 framepos_t where = get_preferred_edit_position();
6119 _session->begin_reversible_command (_("place transient"));
6121 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6122 framepos_t position = (*r)->region()->position();
6123 (*r)->region()->add_transient(where - position);
6126 _session->commit_reversible_command ();
6130 Editor::remove_transient(ArdourCanvas::Item* item)
6136 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6139 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6140 _arv->remove_transient (*(float*) _line->get_data ("position"));
6144 Editor::snap_regions_to_grid ()
6146 list <boost::shared_ptr<Playlist > > used_playlists;
6148 RegionSelection rs = get_regions_from_selection_and_entered ();
6150 if (!_session || rs.empty()) {
6154 _session->begin_reversible_command (_("snap regions to grid"));
6156 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6158 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6160 if (!pl->frozen()) {
6161 /* we haven't seen this playlist before */
6163 /* remember used playlists so we can thaw them later */
6164 used_playlists.push_back(pl);
6168 framepos_t start_frame = (*r)->region()->first_frame ();
6169 snap_to (start_frame);
6170 (*r)->region()->set_position (start_frame);
6173 while (used_playlists.size() > 0) {
6174 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6176 used_playlists.pop_front();
6179 _session->commit_reversible_command ();
6183 Editor::close_region_gaps ()
6185 list <boost::shared_ptr<Playlist > > used_playlists;
6187 RegionSelection rs = get_regions_from_selection_and_entered ();
6189 if (!_session || rs.empty()) {
6193 Dialog dialog (_("Close Region Gaps"));
6196 table.set_spacings (12);
6197 table.set_border_width (12);
6198 Label* l = manage (left_aligned_label (_("Crossfade length")));
6199 table.attach (*l, 0, 1, 0, 1);
6201 SpinButton spin_crossfade (1, 0);
6202 spin_crossfade.set_range (0, 15);
6203 spin_crossfade.set_increments (1, 1);
6204 spin_crossfade.set_value (5);
6205 table.attach (spin_crossfade, 1, 2, 0, 1);
6207 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6209 l = manage (left_aligned_label (_("Pull-back length")));
6210 table.attach (*l, 0, 1, 1, 2);
6212 SpinButton spin_pullback (1, 0);
6213 spin_pullback.set_range (0, 100);
6214 spin_pullback.set_increments (1, 1);
6215 spin_pullback.set_value(30);
6216 table.attach (spin_pullback, 1, 2, 1, 2);
6218 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6220 dialog.get_vbox()->pack_start (table);
6221 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6222 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6225 if (dialog.run () == RESPONSE_CANCEL) {
6229 framepos_t crossfade_len = spin_crossfade.get_value();
6230 framepos_t pull_back_frames = spin_pullback.get_value();
6232 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6233 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6235 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6237 _session->begin_reversible_command (_("close region gaps"));
6240 boost::shared_ptr<Region> last_region;
6242 rs.sort_by_position_and_track();
6244 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6246 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6248 if (!pl->frozen()) {
6249 /* we haven't seen this playlist before */
6251 /* remember used playlists so we can thaw them later */
6252 used_playlists.push_back(pl);
6256 framepos_t position = (*r)->region()->position();
6258 if (idx == 0 || position < last_region->position()){
6259 last_region = (*r)->region();
6264 (*r)->region()->trim_front( (position - pull_back_frames));
6265 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6267 last_region = (*r)->region();
6272 while (used_playlists.size() > 0) {
6273 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6275 used_playlists.pop_front();
6278 _session->commit_reversible_command ();
6282 Editor::tab_to_transient (bool forward)
6284 AnalysisFeatureList positions;
6286 RegionSelection rs = get_regions_from_selection_and_entered ();
6292 framepos_t pos = _session->audible_frame ();
6294 if (!selection->tracks.empty()) {
6296 /* don't waste time searching for transients in duplicate playlists.
6299 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6301 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6303 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6306 boost::shared_ptr<Track> tr = rtv->track();
6308 boost::shared_ptr<Playlist> pl = tr->playlist ();
6310 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6313 positions.push_back (result);
6326 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6327 (*r)->region()->get_transients (positions);
6331 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6334 AnalysisFeatureList::iterator x;
6336 for (x = positions.begin(); x != positions.end(); ++x) {
6342 if (x != positions.end ()) {
6343 _session->request_locate (*x);
6347 AnalysisFeatureList::reverse_iterator x;
6349 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6355 if (x != positions.rend ()) {
6356 _session->request_locate (*x);
6362 Editor::playhead_forward_to_grid ()
6368 framepos_t pos = playhead_cursor->current_frame ();
6369 if (pos < max_framepos - 1) {
6371 snap_to_internal (pos, 1, false);
6372 _session->request_locate (pos);
6378 Editor::playhead_backward_to_grid ()
6384 framepos_t pos = playhead_cursor->current_frame ();
6387 snap_to_internal (pos, -1, false);
6388 _session->request_locate (pos);
6393 Editor::set_track_height (Height h)
6395 TrackSelection& ts (selection->tracks);
6397 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6398 (*x)->set_height_enum (h);
6403 Editor::toggle_tracks_active ()
6405 TrackSelection& ts (selection->tracks);
6407 bool target = false;
6413 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6414 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6418 target = !rtv->_route->active();
6421 rtv->_route->set_active (target, this);
6427 Editor::remove_tracks ()
6429 TrackSelection& ts (selection->tracks);
6435 vector<string> choices;
6439 const char* trackstr;
6441 vector<boost::shared_ptr<Route> > routes;
6442 bool special_bus = false;
6444 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6445 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6447 if (rtv->is_track()) {
6453 routes.push_back (rtv->_route);
6455 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6460 if (special_bus && !Config->get_allow_special_bus_removal()) {
6461 MessageDialog msg (_("That would be bad news ...."),
6465 msg.set_secondary_text (string_compose (_(
6466 "Removing the master or monitor bus is such a bad idea\n\
6467 that %1 is not going to allow it.\n\
6469 If you really want to do this sort of thing\n\
6470 edit your ardour.rc file to set the\n\
6471 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6478 if (ntracks + nbusses == 0) {
6483 trackstr = _("tracks");
6485 trackstr = _("track");
6489 busstr = _("busses");
6496 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6497 "(You may also lose the playlists associated with the %2)\n\n"
6498 "This action cannot be undone, and the session file will be overwritten!"),
6499 ntracks, trackstr, nbusses, busstr);
6501 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6502 "(You may also lose the playlists associated with the %2)\n\n"
6503 "This action cannot be undone, and the session file will be overwritten!"),
6506 } else if (nbusses) {
6507 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6508 "This action cannot be undon, and the session file will be overwritten"),
6512 choices.push_back (_("No, do nothing."));
6513 if (ntracks + nbusses > 1) {
6514 choices.push_back (_("Yes, remove them."));
6516 choices.push_back (_("Yes, remove it."));
6521 title = string_compose (_("Remove %1"), trackstr);
6523 title = string_compose (_("Remove %1"), busstr);
6526 Choice prompter (title, prompt, choices);
6528 if (prompter.run () != 1) {
6532 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6533 _session->remove_route (*x);
6538 Editor::do_insert_time ()
6540 if (selection->tracks.empty()) {
6544 InsertTimeDialog d (*this);
6545 int response = d.run ();
6547 if (response != RESPONSE_OK) {
6551 if (d.distance() == 0) {
6555 InsertTimeOption opt = d.intersected_region_action ();
6558 get_preferred_edit_position(),
6564 d.move_glued_markers(),
6565 d.move_locked_markers(),
6571 Editor::insert_time (
6572 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6573 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6576 bool commit = false;
6578 if (Config->get_edit_mode() == Lock) {
6582 begin_reversible_command (_("insert time"));
6584 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6586 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6590 /* don't operate on any playlist more than once, which could
6591 * happen if "all playlists" is enabled, but there is more
6592 * than 1 track using playlists "from" a given track.
6595 set<boost::shared_ptr<Playlist> > pl;
6597 if (all_playlists) {
6598 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6600 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6601 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6606 if ((*x)->playlist ()) {
6607 pl.insert ((*x)->playlist ());
6611 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6613 (*i)->clear_changes ();
6614 (*i)->clear_owned_changes ();
6616 if (opt == SplitIntersected) {
6620 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6622 vector<Command*> cmds;
6624 _session->add_commands (cmds);
6626 _session->add_command (new StatefulDiffCommand (*i));
6631 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6633 rtav->route ()->shift (pos, frames);
6641 XMLNode& before (_session->locations()->get_state());
6642 Locations::LocationList copy (_session->locations()->list());
6644 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6646 Locations::LocationList::const_iterator tmp;
6648 bool const was_locked = (*i)->locked ();
6649 if (locked_markers_too) {
6653 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6655 if ((*i)->start() >= pos) {
6656 (*i)->set_start ((*i)->start() + frames);
6657 if (!(*i)->is_mark()) {
6658 (*i)->set_end ((*i)->end() + frames);
6671 XMLNode& after (_session->locations()->get_state());
6672 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6677 _session->tempo_map().insert_time (pos, frames);
6681 commit_reversible_command ();
6686 Editor::fit_selected_tracks ()
6688 if (!selection->tracks.empty()) {
6689 fit_tracks (selection->tracks);
6693 /* no selected tracks - use tracks with selected regions */
6695 if (!selection->regions.empty()) {
6696 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6697 tvl.push_back (&(*r)->get_time_axis_view ());
6703 } else if (internal_editing()) {
6704 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6707 if (entered_track) {
6708 tvl.push_back (entered_track);
6716 Editor::fit_tracks (TrackViewList & tracks)
6718 if (tracks.empty()) {
6722 uint32_t child_heights = 0;
6723 int visible_tracks = 0;
6725 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6727 if (!(*t)->marked_for_display()) {
6731 child_heights += (*t)->effective_height() - (*t)->current_height();
6735 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6736 double first_y_pos = DBL_MAX;
6738 if (h < TimeAxisView::preset_height (HeightSmall)) {
6739 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6740 /* too small to be displayed */
6744 undo_visual_stack.push_back (current_visual_state (true));
6745 no_save_visual = true;
6747 /* build a list of all tracks, including children */
6750 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6752 TimeAxisView::Children c = (*i)->get_child_list ();
6753 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6754 all.push_back (j->get());
6758 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6760 bool prev_was_selected = false;
6761 bool is_selected = tracks.contains (all.front());
6762 bool next_is_selected;
6764 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6766 TrackViewList::iterator next;
6771 if (next != all.end()) {
6772 next_is_selected = tracks.contains (*next);
6774 next_is_selected = false;
6777 if ((*t)->marked_for_display ()) {
6779 (*t)->set_height (h);
6780 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6782 if (prev_was_selected && next_is_selected) {
6783 hide_track_in_display (*t);
6788 prev_was_selected = is_selected;
6789 is_selected = next_is_selected;
6793 set the controls_layout height now, because waiting for its size
6794 request signal handler will cause the vertical adjustment setting to fail
6797 controls_layout.property_height () = _full_canvas_height;
6798 vertical_adjustment.set_value (first_y_pos);
6800 redo_visual_stack.push_back (current_visual_state (true));
6804 Editor::save_visual_state (uint32_t n)
6806 while (visual_states.size() <= n) {
6807 visual_states.push_back (0);
6810 if (visual_states[n] != 0) {
6811 delete visual_states[n];
6814 visual_states[n] = current_visual_state (true);
6819 Editor::goto_visual_state (uint32_t n)
6821 if (visual_states.size() <= n) {
6825 if (visual_states[n] == 0) {
6829 use_visual_state (*visual_states[n]);
6833 Editor::start_visual_state_op (uint32_t n)
6835 save_visual_state (n);
6837 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6839 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6840 pup->set_text (buf);
6845 Editor::cancel_visual_state_op (uint32_t n)
6847 goto_visual_state (n);
6851 Editor::toggle_region_mute ()
6853 if (_ignore_region_action) {
6857 RegionSelection rs = get_regions_from_selection_and_entered ();
6863 if (rs.size() > 1) {
6864 begin_reversible_command (_("mute regions"));
6866 begin_reversible_command (_("mute region"));
6869 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6871 (*i)->region()->playlist()->clear_changes ();
6872 (*i)->region()->set_muted (!(*i)->region()->muted ());
6873 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6877 commit_reversible_command ();
6881 Editor::combine_regions ()
6883 /* foreach track with selected regions, take all selected regions
6884 and join them into a new region containing the subregions (as a
6888 typedef set<RouteTimeAxisView*> RTVS;
6891 if (selection->regions.empty()) {
6895 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6896 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6899 tracks.insert (rtv);
6903 begin_reversible_command (_("combine regions"));
6905 vector<RegionView*> new_selection;
6907 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6910 if ((rv = (*i)->combine_regions ()) != 0) {
6911 new_selection.push_back (rv);
6915 selection->clear_regions ();
6916 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6917 selection->add (*i);
6920 commit_reversible_command ();
6924 Editor::uncombine_regions ()
6926 typedef set<RouteTimeAxisView*> RTVS;
6929 if (selection->regions.empty()) {
6933 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6934 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6937 tracks.insert (rtv);
6941 begin_reversible_command (_("uncombine regions"));
6943 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6944 (*i)->uncombine_regions ();
6947 commit_reversible_command ();
6951 Editor::toggle_midi_input_active (bool flip_others)
6954 boost::shared_ptr<RouteList> rl (new RouteList);
6956 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6957 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6963 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6966 rl->push_back (rtav->route());
6967 onoff = !mt->input_active();
6971 _session->set_exclusive_input_active (rl, onoff, flip_others);