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 */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
104 using namespace ARDOUR;
107 using namespace Gtkmm2ext;
108 using namespace Editing;
109 using Gtkmm2ext::Keyboard;
111 /***********************************************************************
113 ***********************************************************************/
116 Editor::undo (uint32_t n)
118 if (_drags->active ()) {
128 Editor::redo (uint32_t n)
130 if (_drags->active ()) {
140 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
144 RegionSelection pre_selected_regions = selection->regions;
145 bool working_on_selection = !pre_selected_regions.empty();
147 list<boost::shared_ptr<Playlist> > used_playlists;
148 list<RouteTimeAxisView*> used_trackviews;
150 if (regions.empty()) {
154 begin_reversible_command (_("split"));
156 // if splitting a single region, and snap-to is using
157 // region boundaries, don't pay attention to them
159 if (regions.size() == 1) {
160 switch (_snap_type) {
161 case SnapToRegionStart:
162 case SnapToRegionSync:
163 case SnapToRegionEnd:
172 EditorFreeze(); /* Emit Signal */
175 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
177 RegionSelection::iterator tmp;
179 /* XXX this test needs to be more complicated, to make sure we really
180 have something to split.
183 if (!(*a)->region()->covers (where)) {
191 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
199 /* we haven't seen this playlist before */
201 /* remember used playlists so we can thaw them later */
202 used_playlists.push_back(pl);
204 TimeAxisView& tv = (*a)->get_time_axis_view();
205 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
207 used_trackviews.push_back (rtv);
214 pl->clear_changes ();
215 pl->split_region ((*a)->region(), where);
216 _session->add_command (new StatefulDiffCommand (pl));
222 latest_regionviews.clear ();
224 vector<sigc::connection> region_added_connections;
226 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
227 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
230 while (used_playlists.size() > 0) {
231 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
233 used_playlists.pop_front();
236 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
241 EditorThaw(); /* Emit Signal */
244 if (working_on_selection) {
245 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
247 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
248 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
249 /* There are three classes of regions that we might want selected after
250 splitting selected regions:
251 - regions selected before the split operation, and unaffected by it
252 - newly-created regions before the split
253 - newly-created regions after the split
256 if (rsas & Existing) {
257 // region selections that existed before the split.
258 selection->add ( pre_selected_regions );
261 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
262 if ((*ri)->region()->position() < where) {
263 // new regions created before the split
264 if (rsas & NewlyCreatedLeft) {
265 selection->add (*ri);
268 // new regions created after the split
269 if (rsas & NewlyCreatedRight) {
270 selection->add (*ri);
274 _ignore_follow_edits = false;
276 _ignore_follow_edits = true;
277 if( working_on_selection ) {
278 selection->add (latest_regionviews); //these are the new regions created after the split
280 _ignore_follow_edits = false;
283 commit_reversible_command ();
286 /** Move one extreme of the current range selection. If more than one range is selected,
287 * the start of the earliest range or the end of the latest range is moved.
289 * @param move_end true to move the end of the current range selection, false to move
291 * @param next true to move the extreme to the next region boundary, false to move to
295 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
297 if (selection->time.start() == selection->time.end_frame()) {
301 framepos_t start = selection->time.start ();
302 framepos_t end = selection->time.end_frame ();
304 /* the position of the thing we may move */
305 framepos_t pos = move_end ? end : start;
306 int dir = next ? 1 : -1;
308 /* so we don't find the current region again */
309 if (dir > 0 || pos > 0) {
313 framepos_t const target = get_region_boundary (pos, dir, true, false);
328 begin_reversible_command (_("alter selection"));
329 selection->set_preserving_all_ranges (start, end);
330 commit_reversible_command ();
334 Editor::nudge_forward_release (GdkEventButton* ev)
336 if (ev->state & Keyboard::PrimaryModifier) {
337 nudge_forward (false, true);
339 nudge_forward (false, false);
345 Editor::nudge_backward_release (GdkEventButton* ev)
347 if (ev->state & Keyboard::PrimaryModifier) {
348 nudge_backward (false, true);
350 nudge_backward (false, false);
357 Editor::nudge_forward (bool next, bool force_playhead)
360 framepos_t next_distance;
366 RegionSelection rs = get_regions_from_selection_and_entered ();
368 if (!force_playhead && !rs.empty()) {
370 begin_reversible_command (_("nudge regions forward"));
372 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
373 boost::shared_ptr<Region> r ((*i)->region());
375 distance = get_nudge_distance (r->position(), next_distance);
378 distance = next_distance;
382 r->set_position (r->position() + distance);
383 _session->add_command (new StatefulDiffCommand (r));
386 commit_reversible_command ();
389 } else if (!force_playhead && !selection->markers.empty()) {
393 begin_reversible_command (_("nudge location forward"));
395 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
397 Location* loc = find_location_from_marker ((*i), is_start);
401 XMLNode& before (loc->get_state());
404 distance = get_nudge_distance (loc->start(), next_distance);
406 distance = next_distance;
408 if (max_framepos - distance > loc->start() + loc->length()) {
409 loc->set_start (loc->start() + distance);
411 loc->set_start (max_framepos - loc->length());
414 distance = get_nudge_distance (loc->end(), next_distance);
416 distance = next_distance;
418 if (max_framepos - distance > loc->end()) {
419 loc->set_end (loc->end() + distance);
421 loc->set_end (max_framepos);
424 XMLNode& after (loc->get_state());
425 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
429 commit_reversible_command ();
432 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
433 _session->request_locate (playhead_cursor->current_frame () + distance);
438 Editor::nudge_backward (bool next, bool force_playhead)
441 framepos_t next_distance;
447 RegionSelection rs = get_regions_from_selection_and_entered ();
449 if (!force_playhead && !rs.empty()) {
451 begin_reversible_command (_("nudge regions backward"));
453 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
454 boost::shared_ptr<Region> r ((*i)->region());
456 distance = get_nudge_distance (r->position(), next_distance);
459 distance = next_distance;
464 if (r->position() > distance) {
465 r->set_position (r->position() - distance);
469 _session->add_command (new StatefulDiffCommand (r));
472 commit_reversible_command ();
474 } else if (!force_playhead && !selection->markers.empty()) {
478 begin_reversible_command (_("nudge location forward"));
480 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
482 Location* loc = find_location_from_marker ((*i), is_start);
486 XMLNode& before (loc->get_state());
489 distance = get_nudge_distance (loc->start(), next_distance);
491 distance = next_distance;
493 if (distance < loc->start()) {
494 loc->set_start (loc->start() - distance);
499 distance = get_nudge_distance (loc->end(), next_distance);
502 distance = next_distance;
505 if (distance < loc->end() - loc->length()) {
506 loc->set_end (loc->end() - distance);
508 loc->set_end (loc->length());
512 XMLNode& after (loc->get_state());
513 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
517 commit_reversible_command ();
521 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
523 if (playhead_cursor->current_frame () > distance) {
524 _session->request_locate (playhead_cursor->current_frame () - distance);
526 _session->goto_start();
532 Editor::nudge_forward_capture_offset ()
534 RegionSelection rs = get_regions_from_selection_and_entered ();
536 if (!_session || rs.empty()) {
540 begin_reversible_command (_("nudge forward"));
542 framepos_t const distance = _session->worst_output_latency();
544 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
545 boost::shared_ptr<Region> r ((*i)->region());
548 r->set_position (r->position() + distance);
549 _session->add_command(new StatefulDiffCommand (r));
552 commit_reversible_command ();
556 Editor::nudge_backward_capture_offset ()
558 RegionSelection rs = get_regions_from_selection_and_entered ();
560 if (!_session || rs.empty()) {
564 begin_reversible_command (_("nudge backward"));
566 framepos_t const distance = _session->worst_output_latency();
568 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
569 boost::shared_ptr<Region> r ((*i)->region());
573 if (r->position() > distance) {
574 r->set_position (r->position() - distance);
578 _session->add_command(new StatefulDiffCommand (r));
581 commit_reversible_command ();
584 struct RegionSelectionPositionSorter {
585 bool operator() (RegionView* a, RegionView* b) {
586 return a->region()->position() < b->region()->position();
591 Editor::sequence_regions ()
594 framepos_t r_end_prev;
602 RegionSelection rs = get_regions_from_selection_and_entered ();
603 rs.sort(RegionSelectionPositionSorter());
607 begin_reversible_command (_("sequence regions"));
608 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
609 boost::shared_ptr<Region> r ((*i)->region());
617 if(r->position_locked())
624 r->set_position(r_end_prev);
627 _session->add_command (new StatefulDiffCommand (r));
629 r_end=r->position() + r->length();
633 commit_reversible_command ();
641 Editor::move_to_start ()
643 _session->goto_start ();
647 Editor::move_to_end ()
650 _session->request_locate (_session->current_end_frame());
654 Editor::build_region_boundary_cache ()
657 vector<RegionPoint> interesting_points;
658 boost::shared_ptr<Region> r;
659 TrackViewList tracks;
662 region_boundary_cache.clear ();
668 switch (_snap_type) {
669 case SnapToRegionStart:
670 interesting_points.push_back (Start);
672 case SnapToRegionEnd:
673 interesting_points.push_back (End);
675 case SnapToRegionSync:
676 interesting_points.push_back (SyncPoint);
678 case SnapToRegionBoundary:
679 interesting_points.push_back (Start);
680 interesting_points.push_back (End);
683 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
684 abort(); /*NOTREACHED*/
688 TimeAxisView *ontrack = 0;
691 if (!selection->tracks.empty()) {
692 tlist = selection->tracks.filter_to_unique_playlists ();
694 tlist = track_views.filter_to_unique_playlists ();
697 while (pos < _session->current_end_frame() && !at_end) {
700 framepos_t lpos = max_framepos;
702 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
704 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
705 if (*p == interesting_points.back()) {
708 /* move to next point type */
714 rpos = r->first_frame();
718 rpos = r->last_frame();
722 rpos = r->sync_position ();
730 RouteTimeAxisView *rtav;
732 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
733 if (rtav->track() != 0) {
734 speed = rtav->track()->speed();
738 rpos = track_frame_to_session_frame (rpos, speed);
744 /* prevent duplicates, but we don't use set<> because we want to be able
748 vector<framepos_t>::iterator ri;
750 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
756 if (ri == region_boundary_cache.end()) {
757 region_boundary_cache.push_back (rpos);
764 /* finally sort to be sure that the order is correct */
766 sort (region_boundary_cache.begin(), region_boundary_cache.end());
769 boost::shared_ptr<Region>
770 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
772 TrackViewList::iterator i;
773 framepos_t closest = max_framepos;
774 boost::shared_ptr<Region> ret;
778 framepos_t track_frame;
779 RouteTimeAxisView *rtav;
781 for (i = tracks.begin(); i != tracks.end(); ++i) {
784 boost::shared_ptr<Region> r;
787 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
788 if (rtav->track()!=0)
789 track_speed = rtav->track()->speed();
792 track_frame = session_frame_to_track_frame(frame, track_speed);
794 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
800 rpos = r->first_frame ();
804 rpos = r->last_frame ();
808 rpos = r->sync_position ();
812 // rpos is a "track frame", converting it to "_session frame"
813 rpos = track_frame_to_session_frame(rpos, track_speed);
816 distance = rpos - frame;
818 distance = frame - rpos;
821 if (distance < closest) {
833 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
835 framecnt_t distance = max_framepos;
836 framepos_t current_nearest = -1;
838 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
839 framepos_t contender;
842 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
848 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
852 d = ::llabs (pos - contender);
855 current_nearest = contender;
860 return current_nearest;
864 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
869 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
871 if (!selection->tracks.empty()) {
873 target = find_next_region_boundary (pos, dir, selection->tracks);
877 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
878 get_onscreen_tracks (tvl);
879 target = find_next_region_boundary (pos, dir, tvl);
881 target = find_next_region_boundary (pos, dir, track_views);
887 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
888 get_onscreen_tracks (tvl);
889 target = find_next_region_boundary (pos, dir, tvl);
891 target = find_next_region_boundary (pos, dir, track_views);
899 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
901 framepos_t pos = playhead_cursor->current_frame ();
908 // so we don't find the current region again..
909 if (dir > 0 || pos > 0) {
913 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
917 _session->request_locate (target);
921 Editor::cursor_to_next_region_boundary (bool with_selection)
923 cursor_to_region_boundary (with_selection, 1);
927 Editor::cursor_to_previous_region_boundary (bool with_selection)
929 cursor_to_region_boundary (with_selection, -1);
933 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
935 boost::shared_ptr<Region> r;
936 framepos_t pos = cursor->current_frame ();
942 TimeAxisView *ontrack = 0;
944 // so we don't find the current region again..
948 if (!selection->tracks.empty()) {
950 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
952 } else if (clicked_axisview) {
955 t.push_back (clicked_axisview);
957 r = find_next_region (pos, point, dir, t, &ontrack);
961 r = find_next_region (pos, point, dir, track_views, &ontrack);
970 pos = r->first_frame ();
974 pos = r->last_frame ();
978 pos = r->sync_position ();
983 RouteTimeAxisView *rtav;
985 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
986 if (rtav->track() != 0) {
987 speed = rtav->track()->speed();
991 pos = track_frame_to_session_frame(pos, speed);
993 if (cursor == playhead_cursor) {
994 _session->request_locate (pos);
996 cursor->set_position (pos);
1001 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1003 cursor_to_region_point (cursor, point, 1);
1007 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1009 cursor_to_region_point (cursor, point, -1);
1013 Editor::cursor_to_selection_start (EditorCursor *cursor)
1017 switch (mouse_mode) {
1019 if (!selection->regions.empty()) {
1020 pos = selection->regions.start();
1025 if (!selection->time.empty()) {
1026 pos = selection->time.start ();
1034 if (cursor == playhead_cursor) {
1035 _session->request_locate (pos);
1037 cursor->set_position (pos);
1042 Editor::cursor_to_selection_end (EditorCursor *cursor)
1046 switch (mouse_mode) {
1048 if (!selection->regions.empty()) {
1049 pos = selection->regions.end_frame();
1054 if (!selection->time.empty()) {
1055 pos = selection->time.end_frame ();
1063 if (cursor == playhead_cursor) {
1064 _session->request_locate (pos);
1066 cursor->set_position (pos);
1071 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1081 if (selection->markers.empty()) {
1085 if (!mouse_frame (mouse, ignored)) {
1089 add_location_mark (mouse);
1092 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1096 framepos_t pos = loc->start();
1098 // so we don't find the current region again..
1099 if (dir > 0 || pos > 0) {
1103 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1107 loc->move_to (target);
1111 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1113 selected_marker_to_region_boundary (with_selection, 1);
1117 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1119 selected_marker_to_region_boundary (with_selection, -1);
1123 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1125 boost::shared_ptr<Region> r;
1130 if (!_session || selection->markers.empty()) {
1134 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1138 TimeAxisView *ontrack = 0;
1142 // so we don't find the current region again..
1146 if (!selection->tracks.empty()) {
1148 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1152 r = find_next_region (pos, point, dir, track_views, &ontrack);
1161 pos = r->first_frame ();
1165 pos = r->last_frame ();
1169 pos = r->adjust_to_sync (r->first_frame());
1174 RouteTimeAxisView *rtav;
1176 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1177 if (rtav->track() != 0) {
1178 speed = rtav->track()->speed();
1182 pos = track_frame_to_session_frame(pos, speed);
1188 Editor::selected_marker_to_next_region_point (RegionPoint point)
1190 selected_marker_to_region_point (point, 1);
1194 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1196 selected_marker_to_region_point (point, -1);
1200 Editor::selected_marker_to_selection_start ()
1206 if (!_session || selection->markers.empty()) {
1210 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1214 switch (mouse_mode) {
1216 if (!selection->regions.empty()) {
1217 pos = selection->regions.start();
1222 if (!selection->time.empty()) {
1223 pos = selection->time.start ();
1235 Editor::selected_marker_to_selection_end ()
1241 if (!_session || selection->markers.empty()) {
1245 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1249 switch (mouse_mode) {
1251 if (!selection->regions.empty()) {
1252 pos = selection->regions.end_frame();
1257 if (!selection->time.empty()) {
1258 pos = selection->time.end_frame ();
1270 Editor::scroll_playhead (bool forward)
1272 framepos_t pos = playhead_cursor->current_frame ();
1273 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1276 if (pos == max_framepos) {
1280 if (pos < max_framepos - delta) {
1299 _session->request_locate (pos);
1303 Editor::cursor_align (bool playhead_to_edit)
1309 if (playhead_to_edit) {
1311 if (selection->markers.empty()) {
1315 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1318 /* move selected markers to playhead */
1320 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1323 Location* loc = find_location_from_marker (*i, ignored);
1325 if (loc->is_mark()) {
1326 loc->set_start (playhead_cursor->current_frame ());
1328 loc->set (playhead_cursor->current_frame (),
1329 playhead_cursor->current_frame () + loc->length());
1336 Editor::scroll_backward (float pages)
1338 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1339 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1342 if (leftmost_frame < cnt) {
1345 frame = leftmost_frame - cnt;
1348 reset_x_origin (frame);
1352 Editor::scroll_forward (float pages)
1354 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1355 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1358 if (max_framepos - cnt < leftmost_frame) {
1359 frame = max_framepos - cnt;
1361 frame = leftmost_frame + cnt;
1364 reset_x_origin (frame);
1368 Editor::scroll_tracks_down ()
1370 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1371 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1372 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1375 vertical_adjustment.set_value (vert_value);
1379 Editor::scroll_tracks_up ()
1381 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1385 Editor::scroll_tracks_down_line ()
1387 double vert_value = vertical_adjustment.get_value() + 60;
1389 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1390 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1393 vertical_adjustment.set_value (vert_value);
1397 Editor::scroll_tracks_up_line ()
1399 reset_y_origin (vertical_adjustment.get_value() - 60);
1403 Editor::scroll_down_one_track ()
1405 TrackViewList::reverse_iterator next = track_views.rend();
1406 std::pair<TimeAxisView*,double> res;
1407 const double top_of_trackviews = vertical_adjustment.get_value();
1409 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1410 if ((*t)->hidden()) {
1415 /* If this is the upper-most visible trackview, we want to display
1416 the one above it (next)
1419 res = (*t)->covers_y_position (top_of_trackviews);
1427 /* move to the track below the first one that covers the */
1429 if (next != track_views.rend()) {
1430 ensure_time_axis_view_is_visible (**next, true);
1438 Editor::scroll_up_one_track ()
1440 TrackViewList::iterator prev = track_views.end();
1441 std::pair<TimeAxisView*,double> res;
1442 double top_of_trackviews = vertical_adjustment.get_value ();
1444 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1446 if ((*t)->hidden()) {
1450 /* find the trackview at the top of the trackview group */
1451 res = (*t)->covers_y_position (top_of_trackviews);
1460 if (prev != track_views.end()) {
1461 ensure_time_axis_view_is_visible (**prev, true);
1471 Editor::tav_zoom_step (bool coarser)
1473 DisplaySuspender ds;
1477 if (selection->tracks.empty()) {
1480 ts = &selection->tracks;
1483 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1484 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1485 tv->step_height (coarser);
1490 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1492 DisplaySuspender ds;
1496 if (selection->tracks.empty() || force_all) {
1499 ts = &selection->tracks;
1502 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1503 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1504 uint32_t h = tv->current_height ();
1509 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1514 tv->set_height (h + 5);
1521 Editor::temporal_zoom_step (bool coarser)
1523 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1525 framecnt_t nspp = samples_per_pixel;
1533 temporal_zoom (nspp);
1537 Editor::temporal_zoom (framecnt_t fpp)
1543 framepos_t current_page = current_page_samples();
1544 framepos_t current_leftmost = leftmost_frame;
1545 framepos_t current_rightmost;
1546 framepos_t current_center;
1547 framepos_t new_page_size;
1548 framepos_t half_page_size;
1549 framepos_t leftmost_after_zoom = 0;
1551 bool in_track_canvas;
1555 if (fpp == samples_per_pixel) {
1559 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1560 // segfaults for lack of memory. If somebody decides this is not high enough I
1561 // believe it can be raisen to higher values but some limit must be in place.
1563 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1564 // all of which is used for the editor track displays. The whole day
1565 // would be 4147200000 samples, so 2592000 samples per pixel.
1567 nfpp = min (fpp, (framecnt_t) 2592000);
1568 nfpp = max ((framecnt_t) 1, nfpp);
1570 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1571 half_page_size = new_page_size / 2;
1573 switch (zoom_focus) {
1575 leftmost_after_zoom = current_leftmost;
1578 case ZoomFocusRight:
1579 current_rightmost = leftmost_frame + current_page;
1580 if (current_rightmost < new_page_size) {
1581 leftmost_after_zoom = 0;
1583 leftmost_after_zoom = current_rightmost - new_page_size;
1587 case ZoomFocusCenter:
1588 current_center = current_leftmost + (current_page/2);
1589 if (current_center < half_page_size) {
1590 leftmost_after_zoom = 0;
1592 leftmost_after_zoom = current_center - half_page_size;
1596 case ZoomFocusPlayhead:
1597 /* centre playhead */
1598 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1601 leftmost_after_zoom = 0;
1602 } else if (l > max_framepos) {
1603 leftmost_after_zoom = max_framepos - new_page_size;
1605 leftmost_after_zoom = (framepos_t) l;
1609 case ZoomFocusMouse:
1610 /* try to keep the mouse over the same point in the display */
1612 if (!mouse_frame (where, in_track_canvas)) {
1613 /* use playhead instead */
1614 where = playhead_cursor->current_frame ();
1616 if (where < half_page_size) {
1617 leftmost_after_zoom = 0;
1619 leftmost_after_zoom = where - half_page_size;
1624 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1627 leftmost_after_zoom = 0;
1628 } else if (l > max_framepos) {
1629 leftmost_after_zoom = max_framepos - new_page_size;
1631 leftmost_after_zoom = (framepos_t) l;
1638 /* try to keep the edit point in the same place */
1639 where = get_preferred_edit_position ();
1643 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1646 leftmost_after_zoom = 0;
1647 } else if (l > max_framepos) {
1648 leftmost_after_zoom = max_framepos - new_page_size;
1650 leftmost_after_zoom = (framepos_t) l;
1654 /* edit point not defined */
1661 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1663 reposition_and_zoom (leftmost_after_zoom, nfpp);
1667 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1669 /* this func helps make sure we leave a little space
1670 at each end of the editor so that the zoom doesn't fit the region
1671 precisely to the screen.
1674 GdkScreen* screen = gdk_screen_get_default ();
1675 const gint pixwidth = gdk_screen_get_width (screen);
1676 const gint mmwidth = gdk_screen_get_width_mm (screen);
1677 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1678 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1680 const framepos_t range = end - start;
1681 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1682 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1684 if (start > extra_samples) {
1685 start -= extra_samples;
1690 if (max_framepos - extra_samples > end) {
1691 end += extra_samples;
1698 Editor::temporal_zoom_region (bool both_axes)
1700 framepos_t start = max_framepos;
1702 set<TimeAxisView*> tracks;
1704 RegionSelection rs = get_regions_from_selection_and_entered ();
1710 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1712 if ((*i)->region()->position() < start) {
1713 start = (*i)->region()->position();
1716 if ((*i)->region()->last_frame() + 1 > end) {
1717 end = (*i)->region()->last_frame() + 1;
1720 tracks.insert (&((*i)->get_time_axis_view()));
1723 if ((start == 0 && end == 0) || end < start) {
1727 calc_extra_zoom_edges (start, end);
1729 /* if we're zooming on both axes we need to save track heights etc.
1732 undo_visual_stack.push_back (current_visual_state (both_axes));
1734 PBD::Unwinder<bool> nsv (no_save_visual, true);
1736 temporal_zoom_by_frame (start, end);
1739 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1741 /* set visible track heights appropriately */
1743 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1744 (*t)->set_height (per_track_height);
1747 /* hide irrelevant tracks */
1749 DisplaySuspender ds;
1751 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1752 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1753 hide_track_in_display (*i);
1757 vertical_adjustment.set_value (0.0);
1760 redo_visual_stack.push_back (current_visual_state (both_axes));
1765 Editor::temporal_zoom_selection (bool both_axes)
1767 if (!selection) return;
1769 //ToDo: if notes are selected, zoom to that
1771 //ToDo: if control points are selected, zoom to that
1773 //if region(s) are selected, zoom to that
1774 if ( !selection->regions.empty() )
1775 temporal_zoom_region (both_axes);
1777 //if a range is selected, zoom to that
1778 if (!selection->time.empty()) {
1780 framepos_t start = selection->time.start();
1781 framepos_t end = selection->time.end_frame();
1783 calc_extra_zoom_edges(start, end);
1785 temporal_zoom_by_frame (start, end);
1788 fit_selected_tracks();
1795 Editor::temporal_zoom_session ()
1797 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1800 framecnt_t start = _session->current_start_frame();
1801 framecnt_t end = _session->current_end_frame();
1803 if (_session->actively_recording () ) {
1804 framepos_t cur = playhead_cursor->current_frame ();
1806 /* recording beyond the end marker; zoom out
1807 * by 5 seconds more so that if 'follow
1808 * playhead' is active we don't immediately
1811 end = cur + _session->frame_rate() * 5;
1815 if ((start == 0 && end == 0) || end < start) {
1819 calc_extra_zoom_edges(start, end);
1821 temporal_zoom_by_frame (start, end);
1826 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1828 if (!_session) return;
1830 if ((start == 0 && end == 0) || end < start) {
1834 framepos_t range = end - start;
1836 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1838 framepos_t new_page = range;
1839 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1840 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1842 if (new_leftmost > middle) {
1846 if (new_leftmost < 0) {
1850 reposition_and_zoom (new_leftmost, new_fpp);
1854 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1860 framecnt_t range_before = frame - leftmost_frame;
1864 if (samples_per_pixel <= 1) {
1867 new_spp = samples_per_pixel + (samples_per_pixel/2);
1869 range_before += range_before/2;
1871 if (samples_per_pixel >= 1) {
1872 new_spp = samples_per_pixel - (samples_per_pixel/2);
1874 /* could bail out here since we cannot zoom any finer,
1875 but leave that to the equality test below
1877 new_spp = samples_per_pixel;
1880 range_before -= range_before/2;
1883 if (new_spp == samples_per_pixel) {
1887 /* zoom focus is automatically taken as @param frame when this
1891 framepos_t new_leftmost = frame - (framepos_t)range_before;
1893 if (new_leftmost > frame) {
1897 if (new_leftmost < 0) {
1901 reposition_and_zoom (new_leftmost, new_spp);
1906 Editor::choose_new_marker_name(string &name) {
1908 if (!ARDOUR_UI::config()->get_name_new_markers()) {
1909 /* don't prompt user for a new name */
1913 ArdourPrompter dialog (true);
1915 dialog.set_prompt (_("New Name:"));
1917 dialog.set_title (_("New Location Marker"));
1919 dialog.set_name ("MarkNameWindow");
1920 dialog.set_size_request (250, -1);
1921 dialog.set_position (Gtk::WIN_POS_MOUSE);
1923 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1924 dialog.set_initial_text (name);
1928 switch (dialog.run ()) {
1929 case RESPONSE_ACCEPT:
1935 dialog.get_result(name);
1942 Editor::add_location_from_selection ()
1946 if (selection->time.empty()) {
1950 if (_session == 0 || clicked_axisview == 0) {
1954 framepos_t start = selection->time[clicked_selection].start;
1955 framepos_t end = selection->time[clicked_selection].end;
1957 _session->locations()->next_available_name(rangename,"selection");
1958 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1960 begin_reversible_command (_("add marker"));
1962 XMLNode &before = _session->locations()->get_state();
1963 _session->locations()->add (location, true);
1964 XMLNode &after = _session->locations()->get_state();
1965 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1967 commit_reversible_command ();
1971 Editor::add_location_mark (framepos_t where)
1975 select_new_marker = true;
1977 _session->locations()->next_available_name(markername,"mark");
1978 if (!choose_new_marker_name(markername)) {
1981 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1982 begin_reversible_command (_("add marker"));
1984 XMLNode &before = _session->locations()->get_state();
1985 _session->locations()->add (location, true);
1986 XMLNode &after = _session->locations()->get_state();
1987 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1989 commit_reversible_command ();
1993 Editor::add_location_from_playhead_cursor ()
1995 add_location_mark (_session->audible_frame());
1999 Editor::remove_location_at_playhead_cursor ()
2004 begin_reversible_command (_("remove marker"));
2006 XMLNode &before = _session->locations()->get_state();
2007 bool removed = false;
2009 //find location(s) at this time
2010 Locations::LocationList locs;
2011 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2012 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2013 if ((*i)->is_mark()) {
2014 _session->locations()->remove (*i);
2021 XMLNode &after = _session->locations()->get_state();
2022 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2024 commit_reversible_command ();
2029 /** Add a range marker around each selected region */
2031 Editor::add_locations_from_region ()
2033 RegionSelection rs = get_regions_from_selection_and_entered ();
2039 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2041 XMLNode &before = _session->locations()->get_state();
2043 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2045 boost::shared_ptr<Region> region = (*i)->region ();
2047 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2049 _session->locations()->add (location, true);
2052 XMLNode &after = _session->locations()->get_state();
2053 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2055 commit_reversible_command ();
2058 /** Add a single range marker around all selected regions */
2060 Editor::add_location_from_region ()
2062 RegionSelection rs = get_regions_from_selection_and_entered ();
2068 begin_reversible_command (_("add marker"));
2070 XMLNode &before = _session->locations()->get_state();
2074 if (rs.size() > 1) {
2075 _session->locations()->next_available_name(markername, "regions");
2077 RegionView* rv = *(rs.begin());
2078 boost::shared_ptr<Region> region = rv->region();
2079 markername = region->name();
2082 if (!choose_new_marker_name(markername)) {
2086 // single range spanning all selected
2087 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2088 _session->locations()->add (location, true);
2090 XMLNode &after = _session->locations()->get_state();
2091 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2093 commit_reversible_command ();
2099 Editor::jump_forward_to_mark ()
2105 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2111 _session->request_locate (pos, _session->transport_rolling());
2115 Editor::jump_backward_to_mark ()
2121 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2127 _session->request_locate (pos, _session->transport_rolling());
2133 framepos_t const pos = _session->audible_frame ();
2136 _session->locations()->next_available_name (markername, "mark");
2138 if (!choose_new_marker_name (markername)) {
2142 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2146 Editor::clear_markers ()
2149 begin_reversible_command (_("clear markers"));
2151 XMLNode &before = _session->locations()->get_state();
2152 _session->locations()->clear_markers ();
2153 XMLNode &after = _session->locations()->get_state();
2154 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2156 commit_reversible_command ();
2161 Editor::clear_ranges ()
2164 begin_reversible_command (_("clear ranges"));
2166 XMLNode &before = _session->locations()->get_state();
2168 _session->locations()->clear_ranges ();
2170 XMLNode &after = _session->locations()->get_state();
2171 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2173 commit_reversible_command ();
2178 Editor::clear_locations ()
2180 begin_reversible_command (_("clear locations"));
2182 XMLNode &before = _session->locations()->get_state();
2183 _session->locations()->clear ();
2184 XMLNode &after = _session->locations()->get_state();
2185 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2187 commit_reversible_command ();
2191 Editor::unhide_markers ()
2193 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2194 Location *l = (*i).first;
2195 if (l->is_hidden() && l->is_mark()) {
2196 l->set_hidden(false, this);
2202 Editor::unhide_ranges ()
2204 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2205 Location *l = (*i).first;
2206 if (l->is_hidden() && l->is_range_marker()) {
2207 l->set_hidden(false, this);
2212 /* INSERT/REPLACE */
2215 Editor::insert_region_list_selection (float times)
2217 RouteTimeAxisView *tv = 0;
2218 boost::shared_ptr<Playlist> playlist;
2220 if (clicked_routeview != 0) {
2221 tv = clicked_routeview;
2222 } else if (!selection->tracks.empty()) {
2223 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2226 } else if (entered_track != 0) {
2227 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2234 if ((playlist = tv->playlist()) == 0) {
2238 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2243 begin_reversible_command (_("insert region"));
2244 playlist->clear_changes ();
2245 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2246 if (Config->get_edit_mode() == Ripple)
2247 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2249 _session->add_command(new StatefulDiffCommand (playlist));
2250 commit_reversible_command ();
2253 /* BUILT-IN EFFECTS */
2256 Editor::reverse_selection ()
2261 /* GAIN ENVELOPE EDITING */
2264 Editor::edit_envelope ()
2271 Editor::transition_to_rolling (bool fwd)
2277 if (_session->config.get_external_sync()) {
2278 switch (Config->get_sync_source()) {
2282 /* transport controlled by the master */
2287 if (_session->is_auditioning()) {
2288 _session->cancel_audition ();
2292 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2296 Editor::play_from_start ()
2298 _session->request_locate (_session->current_start_frame(), true);
2302 Editor::play_from_edit_point ()
2304 _session->request_locate (get_preferred_edit_position(), true);
2308 Editor::play_from_edit_point_and_return ()
2310 framepos_t start_frame;
2311 framepos_t return_frame;
2313 start_frame = get_preferred_edit_position (true);
2315 if (_session->transport_rolling()) {
2316 _session->request_locate (start_frame, false);
2320 /* don't reset the return frame if its already set */
2322 if ((return_frame = _session->requested_return_frame()) < 0) {
2323 return_frame = _session->audible_frame();
2326 if (start_frame >= 0) {
2327 _session->request_roll_at_and_return (start_frame, return_frame);
2332 Editor::play_selection ()
2334 if (selection->time.empty()) {
2338 _session->request_play_range (&selection->time, true);
2342 Editor::get_preroll ()
2344 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2349 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2351 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2354 location -= get_preroll();
2356 //don't try to locate before the beginning of time
2360 //if follow_playhead is on, keep the playhead on the screen
2361 if ( _follow_playhead )
2362 if ( location < leftmost_frame )
2363 location = leftmost_frame;
2365 _session->request_locate( location );
2369 Editor::play_with_preroll ()
2371 if (selection->time.empty()) {
2374 framepos_t preroll = get_preroll();
2376 framepos_t start = 0;
2377 if (selection->time[clicked_selection].start > preroll)
2378 start = selection->time[clicked_selection].start - preroll;
2380 framepos_t end = selection->time[clicked_selection].end + preroll;
2382 AudioRange ar (start, end, 0);
2383 list<AudioRange> lar;
2386 _session->request_play_range (&lar, true);
2391 Editor::play_location (Location& location)
2393 if (location.start() <= location.end()) {
2397 _session->request_bounded_roll (location.start(), location.end());
2401 Editor::loop_location (Location& location)
2403 if (location.start() <= location.end()) {
2409 if ((tll = transport_loop_location()) != 0) {
2410 tll->set (location.start(), location.end());
2412 // enable looping, reposition and start rolling
2413 _session->request_locate (tll->start(), true);
2414 _session->request_play_loop (true);
2419 Editor::do_layer_operation (LayerOperation op)
2421 if (selection->regions.empty ()) {
2425 bool const multiple = selection->regions.size() > 1;
2429 begin_reversible_command (_("raise regions"));
2431 begin_reversible_command (_("raise region"));
2437 begin_reversible_command (_("raise regions to top"));
2439 begin_reversible_command (_("raise region to top"));
2445 begin_reversible_command (_("lower regions"));
2447 begin_reversible_command (_("lower region"));
2453 begin_reversible_command (_("lower regions to bottom"));
2455 begin_reversible_command (_("lower region"));
2460 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2461 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2462 (*i)->clear_owned_changes ();
2465 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2466 boost::shared_ptr<Region> r = (*i)->region ();
2478 r->lower_to_bottom ();
2482 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2483 vector<Command*> cmds;
2485 _session->add_commands (cmds);
2488 commit_reversible_command ();
2492 Editor::raise_region ()
2494 do_layer_operation (Raise);
2498 Editor::raise_region_to_top ()
2500 do_layer_operation (RaiseToTop);
2504 Editor::lower_region ()
2506 do_layer_operation (Lower);
2510 Editor::lower_region_to_bottom ()
2512 do_layer_operation (LowerToBottom);
2515 /** Show the region editor for the selected regions */
2517 Editor::show_region_properties ()
2519 selection->foreach_regionview (&RegionView::show_region_editor);
2522 /** Show the midi list editor for the selected MIDI regions */
2524 Editor::show_midi_list_editor ()
2526 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2530 Editor::rename_region ()
2532 RegionSelection rs = get_regions_from_selection_and_entered ();
2538 ArdourDialog d (*this, _("Rename Region"), true, false);
2540 Label label (_("New name:"));
2543 hbox.set_spacing (6);
2544 hbox.pack_start (label, false, false);
2545 hbox.pack_start (entry, true, true);
2547 d.get_vbox()->set_border_width (12);
2548 d.get_vbox()->pack_start (hbox, false, false);
2550 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2551 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2553 d.set_size_request (300, -1);
2555 entry.set_text (rs.front()->region()->name());
2556 entry.select_region (0, -1);
2558 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2564 int const ret = d.run();
2568 if (ret != RESPONSE_OK) {
2572 std::string str = entry.get_text();
2573 strip_whitespace_edges (str);
2575 rs.front()->region()->set_name (str);
2576 _regions->redisplay ();
2581 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2583 if (_session->is_auditioning()) {
2584 _session->cancel_audition ();
2587 // note: some potential for creativity here, because region doesn't
2588 // have to belong to the playlist that Route is handling
2590 // bool was_soloed = route.soloed();
2592 route.set_solo (true, this);
2594 _session->request_bounded_roll (region->position(), region->position() + region->length());
2596 /* XXX how to unset the solo state ? */
2599 /** Start an audition of the first selected region */
2601 Editor::play_edit_range ()
2603 framepos_t start, end;
2605 if (get_edit_op_range (start, end)) {
2606 _session->request_bounded_roll (start, end);
2611 Editor::play_selected_region ()
2613 framepos_t start = max_framepos;
2616 RegionSelection rs = get_regions_from_selection_and_entered ();
2622 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2623 if ((*i)->region()->position() < start) {
2624 start = (*i)->region()->position();
2626 if ((*i)->region()->last_frame() + 1 > end) {
2627 end = (*i)->region()->last_frame() + 1;
2631 _session->request_bounded_roll (start, end);
2635 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2637 _session->audition_region (region);
2641 Editor::region_from_selection ()
2643 if (clicked_axisview == 0) {
2647 if (selection->time.empty()) {
2651 framepos_t start = selection->time[clicked_selection].start;
2652 framepos_t end = selection->time[clicked_selection].end;
2654 TrackViewList tracks = get_tracks_for_range_action ();
2656 framepos_t selection_cnt = end - start + 1;
2658 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2659 boost::shared_ptr<Region> current;
2660 boost::shared_ptr<Playlist> pl;
2661 framepos_t internal_start;
2664 if ((pl = (*i)->playlist()) == 0) {
2668 if ((current = pl->top_region_at (start)) == 0) {
2672 internal_start = start - current->position();
2673 RegionFactory::region_name (new_name, current->name(), true);
2677 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2678 plist.add (ARDOUR::Properties::length, selection_cnt);
2679 plist.add (ARDOUR::Properties::name, new_name);
2680 plist.add (ARDOUR::Properties::layer, 0);
2682 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2687 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2689 if (selection->time.empty() || selection->tracks.empty()) {
2693 framepos_t start, end;
2694 if (clicked_selection) {
2695 start = selection->time[clicked_selection].start;
2696 end = selection->time[clicked_selection].end;
2698 start = selection->time.start();
2699 end = selection->time.end_frame();
2702 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2703 sort_track_selection (ts);
2705 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2706 boost::shared_ptr<Region> current;
2707 boost::shared_ptr<Playlist> playlist;
2708 framepos_t internal_start;
2711 if ((playlist = (*i)->playlist()) == 0) {
2715 if ((current = playlist->top_region_at(start)) == 0) {
2719 internal_start = start - current->position();
2720 RegionFactory::region_name (new_name, current->name(), true);
2724 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2725 plist.add (ARDOUR::Properties::length, end - start + 1);
2726 plist.add (ARDOUR::Properties::name, new_name);
2728 new_regions.push_back (RegionFactory::create (current, plist));
2733 Editor::split_multichannel_region ()
2735 RegionSelection rs = get_regions_from_selection_and_entered ();
2741 vector< boost::shared_ptr<Region> > v;
2743 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2744 (*x)->region()->separate_by_channel (*_session, v);
2749 Editor::new_region_from_selection ()
2751 region_from_selection ();
2752 cancel_selection ();
2756 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2758 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2759 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2760 case Evoral::OverlapNone:
2768 * - selected tracks, or if there are none...
2769 * - tracks containing selected regions, or if there are none...
2774 Editor::get_tracks_for_range_action () const
2778 if (selection->tracks.empty()) {
2780 /* use tracks with selected regions */
2782 RegionSelection rs = selection->regions;
2784 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2785 TimeAxisView* tv = &(*i)->get_time_axis_view();
2787 if (!t.contains (tv)) {
2793 /* no regions and no tracks: use all tracks */
2799 t = selection->tracks;
2802 return t.filter_to_unique_playlists();
2806 Editor::separate_regions_between (const TimeSelection& ts)
2808 bool in_command = false;
2809 boost::shared_ptr<Playlist> playlist;
2810 RegionSelection new_selection;
2812 TrackViewList tmptracks = get_tracks_for_range_action ();
2813 sort_track_selection (tmptracks);
2815 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2817 RouteTimeAxisView* rtv;
2819 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2821 if (rtv->is_track()) {
2823 /* no edits to destructive tracks */
2825 if (rtv->track()->destructive()) {
2829 if ((playlist = rtv->playlist()) != 0) {
2831 playlist->clear_changes ();
2833 /* XXX need to consider musical time selections here at some point */
2835 double speed = rtv->track()->speed();
2838 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2840 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2841 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2843 latest_regionviews.clear ();
2845 playlist->partition ((framepos_t)((*t).start * speed),
2846 (framepos_t)((*t).end * speed), false);
2850 if (!latest_regionviews.empty()) {
2852 rtv->view()->foreach_regionview (sigc::bind (
2853 sigc::ptr_fun (add_if_covered),
2854 &(*t), &new_selection));
2857 begin_reversible_command (_("separate"));
2861 /* pick up changes to existing regions */
2863 vector<Command*> cmds;
2864 playlist->rdiff (cmds);
2865 _session->add_commands (cmds);
2867 /* pick up changes to the playlist itself (adds/removes)
2870 _session->add_command(new StatefulDiffCommand (playlist));
2879 // selection->set (new_selection);
2881 commit_reversible_command ();
2885 struct PlaylistState {
2886 boost::shared_ptr<Playlist> playlist;
2890 /** Take tracks from get_tracks_for_range_action and cut any regions
2891 * on those tracks so that the tracks are empty over the time
2895 Editor::separate_region_from_selection ()
2897 /* preferentially use *all* ranges in the time selection if we're in range mode
2898 to allow discontiguous operation, since get_edit_op_range() currently
2899 returns a single range.
2902 if (!selection->time.empty()) {
2904 separate_regions_between (selection->time);
2911 if (get_edit_op_range (start, end)) {
2913 AudioRange ar (start, end, 1);
2917 separate_regions_between (ts);
2923 Editor::separate_region_from_punch ()
2925 Location* loc = _session->locations()->auto_punch_location();
2927 separate_regions_using_location (*loc);
2932 Editor::separate_region_from_loop ()
2934 Location* loc = _session->locations()->auto_loop_location();
2936 separate_regions_using_location (*loc);
2941 Editor::separate_regions_using_location (Location& loc)
2943 if (loc.is_mark()) {
2947 AudioRange ar (loc.start(), loc.end(), 1);
2952 separate_regions_between (ts);
2955 /** Separate regions under the selected region */
2957 Editor::separate_under_selected_regions ()
2959 vector<PlaylistState> playlists;
2963 rs = get_regions_from_selection_and_entered();
2965 if (!_session || rs.empty()) {
2969 begin_reversible_command (_("separate region under"));
2971 list<boost::shared_ptr<Region> > regions_to_remove;
2973 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2974 // we can't just remove the region(s) in this loop because
2975 // this removes them from the RegionSelection, and they thus
2976 // disappear from underneath the iterator, and the ++i above
2977 // SEGVs in a puzzling fashion.
2979 // so, first iterate over the regions to be removed from rs and
2980 // add them to the regions_to_remove list, and then
2981 // iterate over the list to actually remove them.
2983 regions_to_remove.push_back ((*i)->region());
2986 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2988 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2991 // is this check necessary?
2995 vector<PlaylistState>::iterator i;
2997 //only take state if this is a new playlist.
2998 for (i = playlists.begin(); i != playlists.end(); ++i) {
2999 if ((*i).playlist == playlist) {
3004 if (i == playlists.end()) {
3006 PlaylistState before;
3007 before.playlist = playlist;
3008 before.before = &playlist->get_state();
3010 playlist->freeze ();
3011 playlists.push_back(before);
3014 //Partition on the region bounds
3015 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3017 //Re-add region that was just removed due to the partition operation
3018 playlist->add_region( (*rl), (*rl)->first_frame() );
3021 vector<PlaylistState>::iterator pl;
3023 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3024 (*pl).playlist->thaw ();
3025 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3028 commit_reversible_command ();
3032 Editor::crop_region_to_selection ()
3034 if (!selection->time.empty()) {
3036 crop_region_to (selection->time.start(), selection->time.end_frame());
3043 if (get_edit_op_range (start, end)) {
3044 crop_region_to (start, end);
3051 Editor::crop_region_to (framepos_t start, framepos_t end)
3053 vector<boost::shared_ptr<Playlist> > playlists;
3054 boost::shared_ptr<Playlist> playlist;
3057 if (selection->tracks.empty()) {
3058 ts = track_views.filter_to_unique_playlists();
3060 ts = selection->tracks.filter_to_unique_playlists ();
3063 sort_track_selection (ts);
3065 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3067 RouteTimeAxisView* rtv;
3069 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3071 boost::shared_ptr<Track> t = rtv->track();
3073 if (t != 0 && ! t->destructive()) {
3075 if ((playlist = rtv->playlist()) != 0) {
3076 playlists.push_back (playlist);
3082 if (playlists.empty()) {
3086 framepos_t the_start;
3090 begin_reversible_command (_("trim to selection"));
3092 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3094 boost::shared_ptr<Region> region;
3098 if ((region = (*i)->top_region_at(the_start)) == 0) {
3102 /* now adjust lengths to that we do the right thing
3103 if the selection extends beyond the region
3106 the_start = max (the_start, (framepos_t) region->position());
3107 if (max_framepos - the_start < region->length()) {
3108 the_end = the_start + region->length() - 1;
3110 the_end = max_framepos;
3112 the_end = min (end, the_end);
3113 cnt = the_end - the_start + 1;
3115 region->clear_changes ();
3116 region->trim_to (the_start, cnt);
3117 _session->add_command (new StatefulDiffCommand (region));
3120 commit_reversible_command ();
3124 Editor::region_fill_track ()
3126 RegionSelection rs = get_regions_from_selection_and_entered ();
3128 if (!_session || rs.empty()) {
3132 framepos_t const end = _session->current_end_frame ();
3134 begin_reversible_command (Operations::region_fill);
3136 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3138 boost::shared_ptr<Region> region ((*i)->region());
3140 boost::shared_ptr<Playlist> pl = region->playlist();
3142 if (end <= region->last_frame()) {
3146 double times = (double) (end - region->last_frame()) / (double) region->length();
3152 pl->clear_changes ();
3153 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3154 _session->add_command (new StatefulDiffCommand (pl));
3157 commit_reversible_command ();
3161 Editor::region_fill_selection ()
3163 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3167 if (selection->time.empty()) {
3171 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3176 framepos_t start = selection->time[clicked_selection].start;
3177 framepos_t end = selection->time[clicked_selection].end;
3179 boost::shared_ptr<Playlist> playlist;
3181 if (selection->tracks.empty()) {
3185 framepos_t selection_length = end - start;
3186 float times = (float)selection_length / region->length();
3188 begin_reversible_command (Operations::fill_selection);
3190 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3192 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3194 if ((playlist = (*i)->playlist()) == 0) {
3198 playlist->clear_changes ();
3199 playlist->add_region (RegionFactory::create (region, true), start, times);
3200 _session->add_command (new StatefulDiffCommand (playlist));
3203 commit_reversible_command ();
3207 Editor::set_region_sync_position ()
3209 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3213 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3215 bool in_command = false;
3217 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3219 if (!(*r)->region()->covers (where)) {
3223 boost::shared_ptr<Region> region ((*r)->region());
3226 begin_reversible_command (_("set sync point"));
3230 region->clear_changes ();
3231 region->set_sync_position (where);
3232 _session->add_command(new StatefulDiffCommand (region));
3236 commit_reversible_command ();
3240 /** Remove the sync positions of the selection */
3242 Editor::remove_region_sync ()
3244 RegionSelection rs = get_regions_from_selection_and_entered ();
3250 begin_reversible_command (_("remove region sync"));
3252 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3254 (*i)->region()->clear_changes ();
3255 (*i)->region()->clear_sync_position ();
3256 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3259 commit_reversible_command ();
3263 Editor::naturalize_region ()
3265 RegionSelection rs = get_regions_from_selection_and_entered ();
3271 if (rs.size() > 1) {
3272 begin_reversible_command (_("move regions to original position"));
3274 begin_reversible_command (_("move region to original position"));
3277 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3278 (*i)->region()->clear_changes ();
3279 (*i)->region()->move_to_natural_position ();
3280 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3283 commit_reversible_command ();
3287 Editor::align_regions (RegionPoint what)
3289 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3295 begin_reversible_command (_("align selection"));
3297 framepos_t const position = get_preferred_edit_position ();
3299 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3300 align_region_internal ((*i)->region(), what, position);
3303 commit_reversible_command ();
3306 struct RegionSortByTime {
3307 bool operator() (const RegionView* a, const RegionView* b) {
3308 return a->region()->position() < b->region()->position();
3313 Editor::align_regions_relative (RegionPoint point)
3315 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3321 framepos_t const position = get_preferred_edit_position ();
3323 framepos_t distance = 0;
3327 list<RegionView*> sorted;
3328 rs.by_position (sorted);
3330 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3335 if (position > r->position()) {
3336 distance = position - r->position();
3338 distance = r->position() - position;
3344 if (position > r->last_frame()) {
3345 distance = position - r->last_frame();
3346 pos = r->position() + distance;
3348 distance = r->last_frame() - position;
3349 pos = r->position() - distance;
3355 pos = r->adjust_to_sync (position);
3356 if (pos > r->position()) {
3357 distance = pos - r->position();
3359 distance = r->position() - pos;
3365 if (pos == r->position()) {
3369 begin_reversible_command (_("align selection (relative)"));
3371 /* move first one specially */
3373 r->clear_changes ();
3374 r->set_position (pos);
3375 _session->add_command(new StatefulDiffCommand (r));
3377 /* move rest by the same amount */
3381 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3383 boost::shared_ptr<Region> region ((*i)->region());
3385 region->clear_changes ();
3388 region->set_position (region->position() + distance);
3390 region->set_position (region->position() - distance);
3393 _session->add_command(new StatefulDiffCommand (region));
3397 commit_reversible_command ();
3401 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3403 begin_reversible_command (_("align region"));
3404 align_region_internal (region, point, position);
3405 commit_reversible_command ();
3409 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3411 region->clear_changes ();
3415 region->set_position (region->adjust_to_sync (position));
3419 if (position > region->length()) {
3420 region->set_position (position - region->length());
3425 region->set_position (position);
3429 _session->add_command(new StatefulDiffCommand (region));
3433 Editor::trim_region_front ()
3439 Editor::trim_region_back ()
3441 trim_region (false);
3445 Editor::trim_region (bool front)
3447 framepos_t where = get_preferred_edit_position();
3448 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3454 begin_reversible_command (front ? _("trim front") : _("trim back"));
3456 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3457 if (!(*i)->region()->locked()) {
3459 (*i)->region()->clear_changes ();
3462 (*i)->region()->trim_front (where);
3463 maybe_locate_with_edit_preroll ( where );
3465 (*i)->region()->trim_end (where);
3466 maybe_locate_with_edit_preroll ( where );
3469 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3473 commit_reversible_command ();
3476 /** Trim the end of the selected regions to the position of the edit cursor */
3478 Editor::trim_region_to_loop ()
3480 Location* loc = _session->locations()->auto_loop_location();
3484 trim_region_to_location (*loc, _("trim to loop"));
3488 Editor::trim_region_to_punch ()
3490 Location* loc = _session->locations()->auto_punch_location();
3494 trim_region_to_location (*loc, _("trim to punch"));
3498 Editor::trim_region_to_location (const Location& loc, const char* str)
3500 RegionSelection rs = get_regions_from_selection_and_entered ();
3502 begin_reversible_command (str);
3504 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3505 RegionView* rv = (*x);
3507 /* require region to span proposed trim */
3508 switch (rv->region()->coverage (loc.start(), loc.end())) {
3509 case Evoral::OverlapInternal:
3515 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3524 if (tav->track() != 0) {
3525 speed = tav->track()->speed();
3528 start = session_frame_to_track_frame (loc.start(), speed);
3529 end = session_frame_to_track_frame (loc.end(), speed);
3531 rv->region()->clear_changes ();
3532 rv->region()->trim_to (start, (end - start));
3533 _session->add_command(new StatefulDiffCommand (rv->region()));
3536 commit_reversible_command ();
3540 Editor::trim_region_to_previous_region_end ()
3542 return trim_to_region(false);
3546 Editor::trim_region_to_next_region_start ()
3548 return trim_to_region(true);
3552 Editor::trim_to_region(bool forward)
3554 RegionSelection rs = get_regions_from_selection_and_entered ();
3556 begin_reversible_command (_("trim to region"));
3558 boost::shared_ptr<Region> next_region;
3560 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3562 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3568 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3576 if (atav->track() != 0) {
3577 speed = atav->track()->speed();
3581 boost::shared_ptr<Region> region = arv->region();
3582 boost::shared_ptr<Playlist> playlist (region->playlist());
3584 region->clear_changes ();
3588 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3594 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3595 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3599 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3605 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3607 arv->region_changed (ARDOUR::bounds_change);
3610 _session->add_command(new StatefulDiffCommand (region));
3613 commit_reversible_command ();
3617 Editor::unfreeze_route ()
3619 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3623 clicked_routeview->track()->unfreeze ();
3627 Editor::_freeze_thread (void* arg)
3629 return static_cast<Editor*>(arg)->freeze_thread ();
3633 Editor::freeze_thread ()
3635 /* create event pool because we may need to talk to the session */
3636 SessionEvent::create_per_thread_pool ("freeze events", 64);
3637 /* create per-thread buffers for process() tree to use */
3638 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3639 current_interthread_info->done = true;
3644 Editor::freeze_route ()
3650 /* stop transport before we start. this is important */
3652 _session->request_transport_speed (0.0);
3654 /* wait for just a little while, because the above call is asynchronous */
3656 Glib::usleep (250000);
3658 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3662 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3664 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3665 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3667 d.set_title (_("Cannot freeze"));
3672 if (clicked_routeview->track()->has_external_redirects()) {
3673 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"
3674 "Freezing will only process the signal as far as the first send/insert/return."),
3675 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3677 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3678 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3679 d.set_title (_("Freeze Limits"));
3681 int response = d.run ();
3684 case Gtk::RESPONSE_CANCEL:
3691 InterThreadInfo itt;
3692 current_interthread_info = &itt;
3694 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3696 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3698 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3700 while (!itt.done && !itt.cancel) {
3701 gtk_main_iteration ();
3704 current_interthread_info = 0;
3708 Editor::bounce_range_selection (bool replace, bool enable_processing)
3710 if (selection->time.empty()) {
3714 TrackSelection views = selection->tracks;
3716 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3718 if (enable_processing) {
3720 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3722 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3724 _("You can't perform this operation because the processing of the signal "
3725 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3726 "You can do this without processing, which is a different operation.")
3728 d.set_title (_("Cannot bounce"));
3735 framepos_t start = selection->time[clicked_selection].start;
3736 framepos_t end = selection->time[clicked_selection].end;
3737 framepos_t cnt = end - start + 1;
3739 begin_reversible_command (_("bounce range"));
3741 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3743 RouteTimeAxisView* rtv;
3745 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3749 boost::shared_ptr<Playlist> playlist;
3751 if ((playlist = rtv->playlist()) == 0) {
3755 InterThreadInfo itt;
3757 playlist->clear_changes ();
3758 playlist->clear_owned_changes ();
3760 boost::shared_ptr<Region> r;
3762 if (enable_processing) {
3763 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3765 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3773 list<AudioRange> ranges;
3774 ranges.push_back (AudioRange (start, start+cnt, 0));
3775 playlist->cut (ranges); // discard result
3776 playlist->add_region (r, start);
3779 vector<Command*> cmds;
3780 playlist->rdiff (cmds);
3781 _session->add_commands (cmds);
3783 _session->add_command (new StatefulDiffCommand (playlist));
3786 commit_reversible_command ();
3789 /** Delete selected regions, automation points or a time range */
3793 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3794 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3795 bool deleted = false;
3796 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3797 deleted = current_mixer_strip->delete_processors ();
3803 /** Cut selected regions, automation points or a time range */
3810 /** Copy selected regions, automation points or a time range */
3818 /** @return true if a Cut, Copy or Clear is possible */
3820 Editor::can_cut_copy () const
3822 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3829 /** Cut, copy or clear selected regions, automation points or a time range.
3830 * @param op Operation (Delete, Cut, Copy or Clear)
3833 Editor::cut_copy (CutCopyOp op)
3835 /* only cancel selection if cut/copy is successful.*/
3841 opname = _("delete");
3850 opname = _("clear");
3854 /* if we're deleting something, and the mouse is still pressed,
3855 the thing we started a drag for will be gone when we release
3856 the mouse button(s). avoid this. see part 2 at the end of
3860 if (op == Delete || op == Cut || op == Clear) {
3861 if (_drags->active ()) {
3866 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3867 cut_buffer->clear ();
3869 if (entered_marker) {
3871 /* cut/delete op while pointing at a marker */
3874 Location* loc = find_location_from_marker (entered_marker, ignored);
3876 if (_session && loc) {
3877 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3884 switch (mouse_mode) {
3887 begin_reversible_command (opname + ' ' + X_("MIDI"));
3889 commit_reversible_command ();
3895 bool did_edit = false;
3897 if (!selection->regions.empty() || !selection->points.empty()) {
3898 begin_reversible_command (opname + ' ' + _("objects"));
3901 if (!selection->regions.empty()) {
3902 cut_copy_regions (op, selection->regions);
3904 if (op == Cut || op == Delete) {
3905 selection->clear_regions ();
3909 if (!selection->points.empty()) {
3910 cut_copy_points (op);
3912 if (op == Cut || op == Delete) {
3913 selection->clear_points ();
3916 } else if (selection->time.empty()) {
3917 framepos_t start, end;
3918 /* no time selection, see if we can get an edit range
3921 if (get_edit_op_range (start, end)) {
3922 selection->set (start, end);
3924 } else if (!selection->time.empty()) {
3925 begin_reversible_command (opname + ' ' + _("range"));
3928 cut_copy_ranges (op);
3930 if (op == Cut || op == Delete) {
3931 selection->clear_time ();
3936 /* reset repeated paste state */
3939 commit_reversible_command ();
3942 if (op == Delete || op == Cut || op == Clear) {
3947 struct AutomationRecord {
3948 AutomationRecord () : state (0) , line(NULL) {}
3949 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3951 XMLNode* state; ///< state before any operation
3952 const AutomationLine* line; ///< line this came from
3953 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3956 /** Cut, copy or clear selected automation points.
3957 * @param op Operation (Cut, Copy or Clear)
3960 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3962 if (selection->points.empty ()) {
3966 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3967 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3969 /* Keep a record of the AutomationLists that we end up using in this operation */
3970 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3973 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3974 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3975 const AutomationLine& line = (*i)->line();
3976 const boost::shared_ptr<AutomationList> al = line.the_list();
3977 if (lists.find (al) == lists.end ()) {
3978 /* We haven't seen this list yet, so make a record for it. This includes
3979 taking a copy of its current state, in case this is needed for undo later.
3981 lists[al] = AutomationRecord (&al->get_state (), &line);
3985 if (op == Cut || op == Copy) {
3986 /* This operation will involve putting things in the cut buffer, so create an empty
3987 ControlList for each of our source lists to put the cut buffer data in.
3989 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3990 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3993 /* Add all selected points to the relevant copy ControlLists */
3994 framepos_t start = std::numeric_limits<framepos_t>::max();
3995 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3996 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3997 AutomationList::const_iterator j = (*i)->model();
3999 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4001 /* Update earliest MIDI start time in beats */
4002 earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
4004 /* Update earliest session start time in frames */
4005 start = std::min(start, (*i)->line().session_position(j));
4009 /* Snap start time backwards, so copy/paste is snap aligned. */
4011 if (earliest == Evoral::MusicalTime::max()) {
4012 earliest = Evoral::MusicalTime(); // Weird... don't offset
4014 earliest.round_down_to_beat();
4016 if (start == std::numeric_limits<double>::max()) {
4017 start = 0; // Weird... don't offset
4019 snap_to(start, RoundDownMaybe);
4022 const double line_offset = midi ? earliest.to_double() : start;
4023 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4024 /* Correct this copy list so that it is relative to the earliest
4025 start time, so relative ordering between points is preserved
4026 when copying from several lists and the paste starts at the
4027 earliest copied piece of data. */
4028 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4029 (*j)->when -= line_offset;
4032 /* And add it to the cut buffer */
4033 cut_buffer->add (i->second.copy);
4037 if (op == Delete || op == Cut) {
4038 /* This operation needs to remove things from the main AutomationList, so do that now */
4040 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4041 i->first->freeze ();
4044 /* Remove each selected point from its AutomationList */
4045 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4046 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4047 al->erase ((*i)->model ());
4050 /* Thaw the lists and add undo records for them */
4051 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4052 boost::shared_ptr<AutomationList> al = i->first;
4054 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4059 /** Cut, copy or clear selected automation points.
4060 * @param op Operation (Cut, Copy or Clear)
4063 Editor::cut_copy_midi (CutCopyOp op)
4065 Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4066 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4067 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4069 if (!mrv->selection().empty()) {
4070 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4072 mrv->cut_copy_clear (op);
4074 /* XXX: not ideal, as there may be more than one track involved in the selection */
4075 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4079 if (!selection->points.empty()) {
4080 cut_copy_points (op, earliest, true);
4081 if (op == Cut || op == Delete) {
4082 selection->clear_points ();
4087 struct lt_playlist {
4088 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4089 return a.playlist < b.playlist;
4093 struct PlaylistMapping {
4095 boost::shared_ptr<Playlist> pl;
4097 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4100 /** Remove `clicked_regionview' */
4102 Editor::remove_clicked_region ()
4104 if (clicked_routeview == 0 || clicked_regionview == 0) {
4108 begin_reversible_command (_("remove region"));
4110 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4112 playlist->clear_changes ();
4113 playlist->clear_owned_changes ();
4114 playlist->remove_region (clicked_regionview->region());
4115 if (Config->get_edit_mode() == Ripple)
4116 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4118 /* We might have removed regions, which alters other regions' layering_index,
4119 so we need to do a recursive diff here.
4121 vector<Command*> cmds;
4122 playlist->rdiff (cmds);
4123 _session->add_commands (cmds);
4125 _session->add_command(new StatefulDiffCommand (playlist));
4126 commit_reversible_command ();
4130 /** Remove the selected regions */
4132 Editor::remove_selected_regions ()
4134 RegionSelection rs = get_regions_from_selection_and_entered ();
4136 if (!_session || rs.empty()) {
4140 begin_reversible_command (_("remove region"));
4142 list<boost::shared_ptr<Region> > regions_to_remove;
4144 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4145 // we can't just remove the region(s) in this loop because
4146 // this removes them from the RegionSelection, and they thus
4147 // disappear from underneath the iterator, and the ++i above
4148 // SEGVs in a puzzling fashion.
4150 // so, first iterate over the regions to be removed from rs and
4151 // add them to the regions_to_remove list, and then
4152 // iterate over the list to actually remove them.
4154 regions_to_remove.push_back ((*i)->region());
4157 vector<boost::shared_ptr<Playlist> > playlists;
4159 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4161 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4164 // is this check necessary?
4168 /* get_regions_from_selection_and_entered() guarantees that
4169 the playlists involved are unique, so there is no need
4173 playlists.push_back (playlist);
4175 playlist->clear_changes ();
4176 playlist->clear_owned_changes ();
4177 playlist->freeze ();
4178 playlist->remove_region (*rl);
4179 if (Config->get_edit_mode() == Ripple)
4180 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4184 vector<boost::shared_ptr<Playlist> >::iterator pl;
4186 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4189 /* We might have removed regions, which alters other regions' layering_index,
4190 so we need to do a recursive diff here.
4192 vector<Command*> cmds;
4193 (*pl)->rdiff (cmds);
4194 _session->add_commands (cmds);
4196 _session->add_command(new StatefulDiffCommand (*pl));
4199 commit_reversible_command ();
4202 /** Cut, copy or clear selected regions.
4203 * @param op Operation (Cut, Copy or Clear)
4206 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4208 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4209 a map when we want ordered access to both elements. i think.
4212 vector<PlaylistMapping> pmap;
4214 framepos_t first_position = max_framepos;
4216 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4217 FreezeList freezelist;
4219 /* get ordering correct before we cut/copy */
4221 rs.sort_by_position_and_track ();
4223 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4225 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4227 if (op == Cut || op == Clear || op == Delete) {
4228 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4231 FreezeList::iterator fl;
4233 // only take state if this is a new playlist.
4234 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4240 if (fl == freezelist.end()) {
4241 pl->clear_changes();
4242 pl->clear_owned_changes ();
4244 freezelist.insert (pl);
4249 TimeAxisView* tv = &(*x)->get_time_axis_view();
4250 vector<PlaylistMapping>::iterator z;
4252 for (z = pmap.begin(); z != pmap.end(); ++z) {
4253 if ((*z).tv == tv) {
4258 if (z == pmap.end()) {
4259 pmap.push_back (PlaylistMapping (tv));
4263 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4265 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4268 /* region not yet associated with a playlist (e.g. unfinished
4275 TimeAxisView& tv = (*x)->get_time_axis_view();
4276 boost::shared_ptr<Playlist> npl;
4277 RegionSelection::iterator tmp;
4284 vector<PlaylistMapping>::iterator z;
4286 for (z = pmap.begin(); z != pmap.end(); ++z) {
4287 if ((*z).tv == &tv) {
4292 assert (z != pmap.end());
4295 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4303 boost::shared_ptr<Region> r = (*x)->region();
4304 boost::shared_ptr<Region> _xx;
4310 pl->remove_region (r);
4311 if (Config->get_edit_mode() == Ripple)
4312 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4316 _xx = RegionFactory::create (r);
4317 npl->add_region (_xx, r->position() - first_position);
4318 pl->remove_region (r);
4319 if (Config->get_edit_mode() == Ripple)
4320 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4324 /* copy region before adding, so we're not putting same object into two different playlists */
4325 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4329 pl->remove_region (r);
4330 if (Config->get_edit_mode() == Ripple)
4331 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4340 list<boost::shared_ptr<Playlist> > foo;
4342 /* the pmap is in the same order as the tracks in which selected regions occured */
4344 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4347 foo.push_back ((*i).pl);
4352 cut_buffer->set (foo);
4356 _last_cut_copy_source_track = 0;
4358 _last_cut_copy_source_track = pmap.front().tv;
4362 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4365 /* We might have removed regions, which alters other regions' layering_index,
4366 so we need to do a recursive diff here.
4368 vector<Command*> cmds;
4369 (*pl)->rdiff (cmds);
4370 _session->add_commands (cmds);
4372 _session->add_command (new StatefulDiffCommand (*pl));
4377 Editor::cut_copy_ranges (CutCopyOp op)
4379 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4381 /* Sort the track selection now, so that it if is used, the playlists
4382 selected by the calls below to cut_copy_clear are in the order that
4383 their tracks appear in the editor. This makes things like paste
4384 of ranges work properly.
4387 sort_track_selection (ts);
4390 if (!entered_track) {
4393 ts.push_back (entered_track);
4396 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4397 (*i)->cut_copy_clear (*selection, op);
4402 Editor::paste (float times, bool from_context)
4404 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4406 paste_internal (get_preferred_edit_position (false, from_context), times);
4410 Editor::mouse_paste ()
4415 if (!mouse_frame (where, ignored)) {
4420 paste_internal (where, 1);
4424 Editor::paste_internal (framepos_t position, float times)
4426 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4428 if (cut_buffer->empty(internal_editing())) {
4432 if (position == max_framepos) {
4433 position = get_preferred_edit_position();
4434 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4437 if (position == last_paste_pos) {
4438 /* repeated paste in the same position */
4441 /* paste in new location, reset repeated paste state */
4443 last_paste_pos = position;
4446 /* get everything in the correct order */
4449 if (!selection->tracks.empty()) {
4450 /* If there is a track selection, paste into exactly those tracks and
4451 only those tracks. This allows the user to be explicit and override
4452 the below "do the reasonable thing" logic. */
4453 ts = selection->tracks.filter_to_unique_playlists ();
4454 sort_track_selection (ts);
4456 /* Figure out which track to base the paste at. */
4457 TimeAxisView* base_track = NULL;
4458 if (_edit_point == Editing::EditAtMouse && entered_track) {
4459 /* With the mouse edit point, paste onto the track under the mouse. */
4460 base_track = entered_track;
4461 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4462 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4463 base_track = &entered_regionview->get_time_axis_view();
4464 } else if (_last_cut_copy_source_track) {
4465 /* Paste to the track that the cut/copy came from (see mantis #333). */
4466 base_track = _last_cut_copy_source_track;
4468 /* This is "impossible" since we've copied... well, do nothing. */
4472 /* Walk up to parent if necessary, so base track is a route. */
4473 while (base_track->get_parent()) {
4474 base_track = base_track->get_parent();
4477 /* Add base track and all tracks below it. The paste logic will select
4478 the appropriate object types from the cut buffer in relative order. */
4479 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4480 if ((*i)->order() >= base_track->order()) {
4485 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4486 sort_track_selection (ts);
4488 /* Add automation children of each track in order, for pasting several lines. */
4489 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4490 /* Add any automation children for pasting several lines */
4491 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4496 typedef RouteTimeAxisView::AutomationTracks ATracks;
4497 const ATracks& atracks = rtv->automation_tracks();
4498 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4499 i = ts.insert(i, a->second.get());
4504 /* We now have a list of trackviews starting at base_track, including
4505 automation children, in the order shown in the editor, e.g. R1,
4506 R1.A1, R1.A2, R2, R2.A1, ... */
4509 begin_reversible_command (Operations::paste);
4511 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4512 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4513 /* Only one line copied, and one automation track selected. Do a
4514 "greedy" paste from one automation type to another. */
4516 PasteContext ctx(paste_count, times, ItemCounts(), true);
4517 ts.front()->paste (position, *cut_buffer, ctx);
4521 /* Paste into tracks */
4523 PasteContext ctx(paste_count, times, ItemCounts(), false);
4524 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4525 (*i)->paste (position, *cut_buffer, ctx);
4529 commit_reversible_command ();
4533 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4535 boost::shared_ptr<Playlist> playlist;
4536 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4537 RegionSelection foo;
4539 framepos_t const start_frame = regions.start ();
4540 framepos_t const end_frame = regions.end_frame ();
4542 begin_reversible_command (Operations::duplicate_region);
4544 selection->clear_regions ();
4546 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4548 boost::shared_ptr<Region> r ((*i)->region());
4550 TimeAxisView& tv = (*i)->get_time_axis_view();
4551 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4552 latest_regionviews.clear ();
4553 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4555 playlist = (*i)->region()->playlist();
4556 playlist->clear_changes ();
4557 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4558 _session->add_command(new StatefulDiffCommand (playlist));
4562 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4566 selection->set (foo);
4569 commit_reversible_command ();
4573 Editor::duplicate_selection (float times)
4575 if (selection->time.empty() || selection->tracks.empty()) {
4579 boost::shared_ptr<Playlist> playlist;
4580 vector<boost::shared_ptr<Region> > new_regions;
4581 vector<boost::shared_ptr<Region> >::iterator ri;
4583 create_region_from_selection (new_regions);
4585 if (new_regions.empty()) {
4589 begin_reversible_command (_("duplicate selection"));
4591 ri = new_regions.begin();
4593 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4595 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4596 if ((playlist = (*i)->playlist()) == 0) {
4599 playlist->clear_changes ();
4601 if (clicked_selection) {
4602 end = selection->time[clicked_selection].end;
4604 end = selection->time.end_frame();
4606 playlist->duplicate (*ri, end, times);
4607 _session->add_command (new StatefulDiffCommand (playlist));
4610 if (ri == new_regions.end()) {
4615 commit_reversible_command ();
4618 /** Reset all selected points to the relevant default value */
4620 Editor::reset_point_selection ()
4622 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4623 ARDOUR::AutomationList::iterator j = (*i)->model ();
4624 (*j)->value = (*i)->line().the_list()->default_value ();
4629 Editor::center_playhead ()
4631 float const page = _visible_canvas_width * samples_per_pixel;
4632 center_screen_internal (playhead_cursor->current_frame (), page);
4636 Editor::center_edit_point ()
4638 float const page = _visible_canvas_width * samples_per_pixel;
4639 center_screen_internal (get_preferred_edit_position(), page);
4642 /** Caller must begin and commit a reversible command */
4644 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4646 playlist->clear_changes ();
4648 _session->add_command (new StatefulDiffCommand (playlist));
4652 Editor::nudge_track (bool use_edit, bool forwards)
4654 boost::shared_ptr<Playlist> playlist;
4655 framepos_t distance;
4656 framepos_t next_distance;
4660 start = get_preferred_edit_position();
4665 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4669 if (selection->tracks.empty()) {
4673 begin_reversible_command (_("nudge track"));
4675 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4677 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4679 if ((playlist = (*i)->playlist()) == 0) {
4683 playlist->clear_changes ();
4684 playlist->clear_owned_changes ();
4686 playlist->nudge_after (start, distance, forwards);
4688 vector<Command*> cmds;
4690 playlist->rdiff (cmds);
4691 _session->add_commands (cmds);
4693 _session->add_command (new StatefulDiffCommand (playlist));
4696 commit_reversible_command ();
4700 Editor::remove_last_capture ()
4702 vector<string> choices;
4709 if (Config->get_verify_remove_last_capture()) {
4710 prompt = _("Do you really want to destroy the last capture?"
4711 "\n(This is destructive and cannot be undone)");
4713 choices.push_back (_("No, do nothing."));
4714 choices.push_back (_("Yes, destroy it."));
4716 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4718 if (prompter.run () == 1) {
4719 _session->remove_last_capture ();
4720 _regions->redisplay ();
4724 _session->remove_last_capture();
4725 _regions->redisplay ();
4730 Editor::normalize_region ()
4736 RegionSelection rs = get_regions_from_selection_and_entered ();
4742 NormalizeDialog dialog (rs.size() > 1);
4744 if (dialog.run () == RESPONSE_CANCEL) {
4748 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4751 /* XXX: should really only count audio regions here */
4752 int const regions = rs.size ();
4754 /* Make a list of the selected audio regions' maximum amplitudes, and also
4755 obtain the maximum amplitude of them all.
4757 list<double> max_amps;
4759 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4760 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4762 dialog.descend (1.0 / regions);
4763 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4766 /* the user cancelled the operation */
4770 max_amps.push_back (a);
4771 max_amp = max (max_amp, a);
4776 begin_reversible_command (_("normalize"));
4778 list<double>::const_iterator a = max_amps.begin ();
4780 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4781 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4786 arv->region()->clear_changes ();
4788 double const amp = dialog.normalize_individually() ? *a : max_amp;
4790 arv->audio_region()->normalize (amp, dialog.target ());
4791 _session->add_command (new StatefulDiffCommand (arv->region()));
4796 commit_reversible_command ();
4801 Editor::reset_region_scale_amplitude ()
4807 RegionSelection rs = get_regions_from_selection_and_entered ();
4813 begin_reversible_command ("reset gain");
4815 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4816 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4819 arv->region()->clear_changes ();
4820 arv->audio_region()->set_scale_amplitude (1.0f);
4821 _session->add_command (new StatefulDiffCommand (arv->region()));
4824 commit_reversible_command ();
4828 Editor::adjust_region_gain (bool up)
4830 RegionSelection rs = get_regions_from_selection_and_entered ();
4832 if (!_session || rs.empty()) {
4836 begin_reversible_command ("adjust region gain");
4838 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4839 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4844 arv->region()->clear_changes ();
4846 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4854 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4855 _session->add_command (new StatefulDiffCommand (arv->region()));
4858 commit_reversible_command ();
4863 Editor::reverse_region ()
4869 Reverse rev (*_session);
4870 apply_filter (rev, _("reverse regions"));
4874 Editor::strip_region_silence ()
4880 RegionSelection rs = get_regions_from_selection_and_entered ();
4886 std::list<RegionView*> audio_only;
4888 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4889 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4891 audio_only.push_back (arv);
4895 StripSilenceDialog d (_session, audio_only);
4896 int const r = d.run ();
4900 if (r == Gtk::RESPONSE_OK) {
4901 ARDOUR::AudioIntervalMap silences;
4902 d.silences (silences);
4903 StripSilence s (*_session, silences, d.fade_length());
4904 apply_filter (s, _("strip silence"), &d);
4909 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4911 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4912 mrv.selection_as_notelist (selected, true);
4914 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4915 v.push_back (selected);
4917 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4918 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4920 return op (mrv.midi_region()->model(), pos_beats, v);
4924 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
4930 begin_reversible_command (op.name ());
4932 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
4933 RegionSelection::const_iterator tmp = r;
4936 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4939 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4942 _session->add_command (cmd);
4949 commit_reversible_command ();
4953 Editor::fork_region ()
4955 RegionSelection rs = get_regions_from_selection_and_entered ();
4961 begin_reversible_command (_("Fork Region(s)"));
4963 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4966 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4967 RegionSelection::iterator tmp = r;
4970 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4974 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4975 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4976 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4978 playlist->clear_changes ();
4979 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4980 _session->add_command(new StatefulDiffCommand (playlist));
4982 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4989 commit_reversible_command ();
4993 Editor::quantize_region ()
4996 quantize_regions(get_regions_from_selection_and_entered ());
5001 Editor::quantize_regions (const RegionSelection& rs)
5003 if (rs.n_midi_regions() == 0) {
5007 QuantizeDialog* qd = new QuantizeDialog (*this);
5010 const int r = qd->run ();
5013 if (r == Gtk::RESPONSE_OK) {
5014 Quantize quant (qd->snap_start(), qd->snap_end(),
5015 qd->start_grid_size(), qd->end_grid_size(),
5016 qd->strength(), qd->swing(), qd->threshold());
5018 apply_midi_note_edit_op (quant, rs);
5023 Editor::legatize_region (bool shrink_only)
5026 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5031 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5033 if (rs.n_midi_regions() == 0) {
5037 Legatize legatize(shrink_only);
5038 apply_midi_note_edit_op (legatize, rs);
5042 Editor::insert_patch_change (bool from_context)
5044 RegionSelection rs = get_regions_from_selection_and_entered ();
5050 const framepos_t p = get_preferred_edit_position (false, from_context);
5052 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5053 there may be more than one, but the PatchChangeDialog can only offer
5054 one set of patch menus.
5056 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5058 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5059 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5061 if (d.run() == RESPONSE_CANCEL) {
5065 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5066 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5068 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5069 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5076 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5078 RegionSelection rs = get_regions_from_selection_and_entered ();
5084 begin_reversible_command (command);
5086 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5090 int const N = rs.size ();
5092 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5093 RegionSelection::iterator tmp = r;
5096 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5098 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5101 progress->descend (1.0 / N);
5104 if (arv->audio_region()->apply (filter, progress) == 0) {
5106 playlist->clear_changes ();
5107 playlist->clear_owned_changes ();
5109 if (filter.results.empty ()) {
5111 /* no regions returned; remove the old one */
5112 playlist->remove_region (arv->region ());
5116 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5118 /* first region replaces the old one */
5119 playlist->replace_region (arv->region(), *res, (*res)->position());
5123 while (res != filter.results.end()) {
5124 playlist->add_region (*res, (*res)->position());
5130 /* We might have removed regions, which alters other regions' layering_index,
5131 so we need to do a recursive diff here.
5133 vector<Command*> cmds;
5134 playlist->rdiff (cmds);
5135 _session->add_commands (cmds);
5137 _session->add_command(new StatefulDiffCommand (playlist));
5143 progress->ascend ();
5151 commit_reversible_command ();
5155 Editor::external_edit_region ()
5161 Editor::reset_region_gain_envelopes ()
5163 RegionSelection rs = get_regions_from_selection_and_entered ();
5165 if (!_session || rs.empty()) {
5169 begin_reversible_command (_("reset region gain"));
5171 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5172 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5174 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5175 XMLNode& before (alist->get_state());
5177 arv->audio_region()->set_default_envelope ();
5178 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5182 commit_reversible_command ();
5186 Editor::set_region_gain_visibility (RegionView* rv)
5188 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5190 arv->update_envelope_visibility();
5195 Editor::set_gain_envelope_visibility ()
5201 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5202 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5204 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5210 Editor::toggle_gain_envelope_active ()
5212 if (_ignore_region_action) {
5216 RegionSelection rs = get_regions_from_selection_and_entered ();
5218 if (!_session || rs.empty()) {
5222 begin_reversible_command (_("region gain envelope active"));
5224 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5225 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5227 arv->region()->clear_changes ();
5228 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5229 _session->add_command (new StatefulDiffCommand (arv->region()));
5233 commit_reversible_command ();
5237 Editor::toggle_region_lock ()
5239 if (_ignore_region_action) {
5243 RegionSelection rs = get_regions_from_selection_and_entered ();
5245 if (!_session || rs.empty()) {
5249 begin_reversible_command (_("toggle region lock"));
5251 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5252 (*i)->region()->clear_changes ();
5253 (*i)->region()->set_locked (!(*i)->region()->locked());
5254 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5257 commit_reversible_command ();
5261 Editor::toggle_region_video_lock ()
5263 if (_ignore_region_action) {
5267 RegionSelection rs = get_regions_from_selection_and_entered ();
5269 if (!_session || rs.empty()) {
5273 begin_reversible_command (_("Toggle Video Lock"));
5275 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5276 (*i)->region()->clear_changes ();
5277 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5278 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5281 commit_reversible_command ();
5285 Editor::toggle_region_lock_style ()
5287 if (_ignore_region_action) {
5291 RegionSelection rs = get_regions_from_selection_and_entered ();
5293 if (!_session || rs.empty()) {
5297 begin_reversible_command (_("region lock style"));
5299 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5300 (*i)->region()->clear_changes ();
5301 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5302 (*i)->region()->set_position_lock_style (ns);
5303 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5306 commit_reversible_command ();
5310 Editor::toggle_opaque_region ()
5312 if (_ignore_region_action) {
5316 RegionSelection rs = get_regions_from_selection_and_entered ();
5318 if (!_session || rs.empty()) {
5322 begin_reversible_command (_("change region opacity"));
5324 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5325 (*i)->region()->clear_changes ();
5326 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5327 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5330 commit_reversible_command ();
5334 Editor::toggle_record_enable ()
5336 bool new_state = false;
5338 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5339 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5342 if (!rtav->is_track())
5346 new_state = !rtav->track()->record_enabled();
5350 rtav->track()->set_record_enabled (new_state, this);
5355 Editor::toggle_solo ()
5357 bool new_state = false;
5359 boost::shared_ptr<RouteList> rl (new RouteList);
5361 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5362 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5369 new_state = !rtav->route()->soloed ();
5373 rl->push_back (rtav->route());
5376 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5380 Editor::toggle_mute ()
5382 bool new_state = false;
5384 boost::shared_ptr<RouteList> rl (new RouteList);
5386 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5387 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5394 new_state = !rtav->route()->muted();
5398 rl->push_back (rtav->route());
5401 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5405 Editor::toggle_solo_isolate ()
5411 Editor::fade_range ()
5413 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5415 begin_reversible_command (_("fade range"));
5417 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5418 (*i)->fade_range (selection->time);
5421 commit_reversible_command ();
5426 Editor::set_fade_length (bool in)
5428 RegionSelection rs = get_regions_from_selection_and_entered ();
5434 /* we need a region to measure the offset from the start */
5436 RegionView* rv = rs.front ();
5438 framepos_t pos = get_preferred_edit_position();
5442 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5443 /* edit point is outside the relevant region */
5448 if (pos <= rv->region()->position()) {
5452 len = pos - rv->region()->position();
5453 cmd = _("set fade in length");
5455 if (pos >= rv->region()->last_frame()) {
5459 len = rv->region()->last_frame() - pos;
5460 cmd = _("set fade out length");
5463 begin_reversible_command (cmd);
5465 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5466 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5472 boost::shared_ptr<AutomationList> alist;
5474 alist = tmp->audio_region()->fade_in();
5476 alist = tmp->audio_region()->fade_out();
5479 XMLNode &before = alist->get_state();
5482 tmp->audio_region()->set_fade_in_length (len);
5483 tmp->audio_region()->set_fade_in_active (true);
5485 tmp->audio_region()->set_fade_out_length (len);
5486 tmp->audio_region()->set_fade_out_active (true);
5489 XMLNode &after = alist->get_state();
5490 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5493 commit_reversible_command ();
5497 Editor::set_fade_in_shape (FadeShape shape)
5499 RegionSelection rs = get_regions_from_selection_and_entered ();
5505 begin_reversible_command (_("set fade in shape"));
5507 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5508 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5514 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5515 XMLNode &before = alist->get_state();
5517 tmp->audio_region()->set_fade_in_shape (shape);
5519 XMLNode &after = alist->get_state();
5520 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5523 commit_reversible_command ();
5528 Editor::set_fade_out_shape (FadeShape shape)
5530 RegionSelection rs = get_regions_from_selection_and_entered ();
5536 begin_reversible_command (_("set fade out shape"));
5538 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5539 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5545 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5546 XMLNode &before = alist->get_state();
5548 tmp->audio_region()->set_fade_out_shape (shape);
5550 XMLNode &after = alist->get_state();
5551 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5554 commit_reversible_command ();
5558 Editor::set_fade_in_active (bool yn)
5560 RegionSelection rs = get_regions_from_selection_and_entered ();
5566 begin_reversible_command (_("set fade in active"));
5568 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5569 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5576 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5578 ar->clear_changes ();
5579 ar->set_fade_in_active (yn);
5580 _session->add_command (new StatefulDiffCommand (ar));
5583 commit_reversible_command ();
5587 Editor::set_fade_out_active (bool yn)
5589 RegionSelection rs = get_regions_from_selection_and_entered ();
5595 begin_reversible_command (_("set fade out active"));
5597 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5598 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5604 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5606 ar->clear_changes ();
5607 ar->set_fade_out_active (yn);
5608 _session->add_command(new StatefulDiffCommand (ar));
5611 commit_reversible_command ();
5615 Editor::toggle_region_fades (int dir)
5617 if (_ignore_region_action) {
5621 boost::shared_ptr<AudioRegion> ar;
5624 RegionSelection rs = get_regions_from_selection_and_entered ();
5630 RegionSelection::iterator i;
5631 for (i = rs.begin(); i != rs.end(); ++i) {
5632 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5634 yn = ar->fade_out_active ();
5636 yn = ar->fade_in_active ();
5642 if (i == rs.end()) {
5646 /* XXX should this undo-able? */
5648 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5649 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5652 if (dir == 1 || dir == 0) {
5653 ar->set_fade_in_active (!yn);
5656 if (dir == -1 || dir == 0) {
5657 ar->set_fade_out_active (!yn);
5663 /** Update region fade visibility after its configuration has been changed */
5665 Editor::update_region_fade_visibility ()
5667 bool _fade_visibility = _session->config.get_show_region_fades ();
5669 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5670 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5672 if (_fade_visibility) {
5673 v->audio_view()->show_all_fades ();
5675 v->audio_view()->hide_all_fades ();
5682 Editor::set_edit_point ()
5687 if (!mouse_frame (where, ignored)) {
5693 if (selection->markers.empty()) {
5695 mouse_add_new_marker (where);
5700 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5703 loc->move_to (where);
5709 Editor::set_playhead_cursor ()
5711 if (entered_marker) {
5712 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5717 if (!mouse_frame (where, ignored)) {
5724 _session->request_locate (where, _session->transport_rolling());
5728 if (ARDOUR_UI::config()->get_follow_edits()) {
5729 cancel_time_selection();
5734 Editor::split_region ()
5736 if ( !selection->time.empty()) {
5737 separate_regions_between (selection->time);
5741 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5743 framepos_t where = get_preferred_edit_position ();
5749 split_regions_at (where, rs);
5752 struct EditorOrderRouteSorter {
5753 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5754 return a->order_key () < b->order_key ();
5759 Editor::select_next_route()
5761 if (selection->tracks.empty()) {
5762 selection->set (track_views.front());
5766 TimeAxisView* current = selection->tracks.front();
5770 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5771 if (*i == current) {
5773 if (i != track_views.end()) {
5776 current = (*(track_views.begin()));
5777 //selection->set (*(track_views.begin()));
5782 rui = dynamic_cast<RouteUI *>(current);
5783 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5785 selection->set(current);
5787 ensure_time_axis_view_is_visible (*current, false);
5791 Editor::select_prev_route()
5793 if (selection->tracks.empty()) {
5794 selection->set (track_views.front());
5798 TimeAxisView* current = selection->tracks.front();
5802 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5803 if (*i == current) {
5805 if (i != track_views.rend()) {
5808 current = *(track_views.rbegin());
5813 rui = dynamic_cast<RouteUI *>(current);
5814 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5816 selection->set (current);
5818 ensure_time_axis_view_is_visible (*current, false);
5822 Editor::set_loop_from_selection (bool play)
5824 if (_session == 0 || selection->time.empty()) {
5828 framepos_t start = selection->time[clicked_selection].start;
5829 framepos_t end = selection->time[clicked_selection].end;
5831 set_loop_range (start, end, _("set loop range from selection"));
5834 _session->request_locate (start, true);
5835 _session->request_play_loop (true);
5840 Editor::set_loop_from_edit_range (bool play)
5842 if (_session == 0) {
5849 if (!get_edit_op_range (start, end)) {
5853 set_loop_range (start, end, _("set loop range from edit range"));
5856 _session->request_locate (start, true);
5857 _session->request_play_loop (true);
5862 Editor::set_loop_from_region (bool play)
5864 framepos_t start = max_framepos;
5867 RegionSelection rs = get_regions_from_selection_and_entered ();
5873 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5874 if ((*i)->region()->position() < start) {
5875 start = (*i)->region()->position();
5877 if ((*i)->region()->last_frame() + 1 > end) {
5878 end = (*i)->region()->last_frame() + 1;
5882 set_loop_range (start, end, _("set loop range from region"));
5885 _session->request_locate (start, true);
5886 _session->request_play_loop (true);
5891 Editor::set_punch_from_selection ()
5893 if (_session == 0 || selection->time.empty()) {
5897 framepos_t start = selection->time[clicked_selection].start;
5898 framepos_t end = selection->time[clicked_selection].end;
5900 set_punch_range (start, end, _("set punch range from selection"));
5904 Editor::set_session_extents_from_selection ()
5906 if (_session == 0 || selection->time.empty()) {
5910 begin_reversible_command (_("set session start/stop from selection"));
5912 framepos_t start = selection->time[clicked_selection].start;
5913 framepos_t end = selection->time[clicked_selection].end;
5916 if ((loc = _session->locations()->session_range_location()) == 0) {
5917 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5919 XMLNode &before = loc->get_state();
5921 _session->set_session_extents ( start, end );
5923 XMLNode &after = loc->get_state();
5925 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5927 commit_reversible_command ();
5932 Editor::set_punch_from_edit_range ()
5934 if (_session == 0) {
5941 if (!get_edit_op_range (start, end)) {
5945 set_punch_range (start, end, _("set punch range from edit range"));
5949 Editor::set_punch_from_region ()
5951 framepos_t start = max_framepos;
5954 RegionSelection rs = get_regions_from_selection_and_entered ();
5960 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5961 if ((*i)->region()->position() < start) {
5962 start = (*i)->region()->position();
5964 if ((*i)->region()->last_frame() + 1 > end) {
5965 end = (*i)->region()->last_frame() + 1;
5969 set_punch_range (start, end, _("set punch range from region"));
5973 Editor::pitch_shift_region ()
5975 RegionSelection rs = get_regions_from_selection_and_entered ();
5977 RegionSelection audio_rs;
5978 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5979 if (dynamic_cast<AudioRegionView*> (*i)) {
5980 audio_rs.push_back (*i);
5984 if (audio_rs.empty()) {
5988 pitch_shift (audio_rs, 1.2);
5992 Editor::transpose_region ()
5994 RegionSelection rs = get_regions_from_selection_and_entered ();
5996 list<MidiRegionView*> midi_region_views;
5997 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5998 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6000 midi_region_views.push_back (mrv);
6005 int const r = d.run ();
6006 if (r != RESPONSE_ACCEPT) {
6010 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6011 (*i)->midi_region()->transpose (d.semitones ());
6016 Editor::set_tempo_from_region ()
6018 RegionSelection rs = get_regions_from_selection_and_entered ();
6020 if (!_session || rs.empty()) {
6024 RegionView* rv = rs.front();
6026 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6030 Editor::use_range_as_bar ()
6032 framepos_t start, end;
6033 if (get_edit_op_range (start, end)) {
6034 define_one_bar (start, end);
6039 Editor::define_one_bar (framepos_t start, framepos_t end)
6041 framepos_t length = end - start;
6043 const Meter& m (_session->tempo_map().meter_at (start));
6045 /* length = 1 bar */
6047 /* now we want frames per beat.
6048 we have frames per bar, and beats per bar, so ...
6051 /* XXXX METER MATH */
6053 double frames_per_beat = length / m.divisions_per_bar();
6055 /* beats per minute = */
6057 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6059 /* now decide whether to:
6061 (a) set global tempo
6062 (b) add a new tempo marker
6066 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6068 bool do_global = false;
6070 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6072 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6073 at the start, or create a new marker
6076 vector<string> options;
6077 options.push_back (_("Cancel"));
6078 options.push_back (_("Add new marker"));
6079 options.push_back (_("Set global tempo"));
6082 _("Define one bar"),
6083 _("Do you want to set the global tempo or add a new tempo marker?"),
6087 c.set_default_response (2);
6103 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6104 if the marker is at the region starter, change it, otherwise add
6109 begin_reversible_command (_("set tempo from region"));
6110 XMLNode& before (_session->tempo_map().get_state());
6113 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6114 } else if (t.frame() == start) {
6115 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6117 Timecode::BBT_Time bbt;
6118 _session->tempo_map().bbt_time (start, bbt);
6119 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6122 XMLNode& after (_session->tempo_map().get_state());
6124 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6125 commit_reversible_command ();
6129 Editor::split_region_at_transients ()
6131 AnalysisFeatureList positions;
6133 RegionSelection rs = get_regions_from_selection_and_entered ();
6135 if (!_session || rs.empty()) {
6139 begin_reversible_command (_("split regions"));
6141 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6143 RegionSelection::iterator tmp;
6148 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6150 if (ar && (ar->get_transients (positions) == 0)) {
6151 split_region_at_points ((*i)->region(), positions, true);
6158 commit_reversible_command ();
6163 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6165 bool use_rhythmic_rodent = false;
6167 boost::shared_ptr<Playlist> pl = r->playlist();
6169 list<boost::shared_ptr<Region> > new_regions;
6175 if (positions.empty()) {
6180 if (positions.size() > 20 && can_ferret) {
6181 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);
6182 MessageDialog msg (msgstr,
6185 Gtk::BUTTONS_OK_CANCEL);
6188 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6189 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6191 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6194 msg.set_title (_("Excessive split?"));
6197 int response = msg.run();
6203 case RESPONSE_APPLY:
6204 use_rhythmic_rodent = true;
6211 if (use_rhythmic_rodent) {
6212 show_rhythm_ferret ();
6216 AnalysisFeatureList::const_iterator x;
6218 pl->clear_changes ();
6219 pl->clear_owned_changes ();
6221 x = positions.begin();
6223 if (x == positions.end()) {
6228 pl->remove_region (r);
6232 while (x != positions.end()) {
6234 /* deal with positons that are out of scope of present region bounds */
6235 if (*x <= 0 || *x > r->length()) {
6240 /* file start = original start + how far we from the initial position ?
6243 framepos_t file_start = r->start() + pos;
6245 /* length = next position - current position
6248 framepos_t len = (*x) - pos;
6250 /* XXX we do we really want to allow even single-sample regions?
6251 shouldn't we have some kind of lower limit on region size?
6260 if (RegionFactory::region_name (new_name, r->name())) {
6264 /* do NOT announce new regions 1 by one, just wait till they are all done */
6268 plist.add (ARDOUR::Properties::start, file_start);
6269 plist.add (ARDOUR::Properties::length, len);
6270 plist.add (ARDOUR::Properties::name, new_name);
6271 plist.add (ARDOUR::Properties::layer, 0);
6273 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6274 /* because we set annouce to false, manually add the new region to the
6277 RegionFactory::map_add (nr);
6279 pl->add_region (nr, r->position() + pos);
6282 new_regions.push_front(nr);
6291 RegionFactory::region_name (new_name, r->name());
6293 /* Add the final region */
6296 plist.add (ARDOUR::Properties::start, r->start() + pos);
6297 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6298 plist.add (ARDOUR::Properties::name, new_name);
6299 plist.add (ARDOUR::Properties::layer, 0);
6301 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6302 /* because we set annouce to false, manually add the new region to the
6305 RegionFactory::map_add (nr);
6306 pl->add_region (nr, r->position() + pos);
6309 new_regions.push_front(nr);
6314 /* We might have removed regions, which alters other regions' layering_index,
6315 so we need to do a recursive diff here.
6317 vector<Command*> cmds;
6319 _session->add_commands (cmds);
6321 _session->add_command (new StatefulDiffCommand (pl));
6325 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6326 set_selected_regionview_from_region_list ((*i), Selection::Add);
6332 Editor::place_transient()
6338 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6344 framepos_t where = get_preferred_edit_position();
6346 begin_reversible_command (_("place transient"));
6348 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6349 framepos_t position = (*r)->region()->position();
6350 (*r)->region()->add_transient(where - position);
6353 commit_reversible_command ();
6357 Editor::remove_transient(ArdourCanvas::Item* item)
6363 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6366 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6367 _arv->remove_transient (*(float*) _line->get_data ("position"));
6371 Editor::snap_regions_to_grid ()
6373 list <boost::shared_ptr<Playlist > > used_playlists;
6375 RegionSelection rs = get_regions_from_selection_and_entered ();
6377 if (!_session || rs.empty()) {
6381 begin_reversible_command (_("snap regions to grid"));
6383 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6385 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6387 if (!pl->frozen()) {
6388 /* we haven't seen this playlist before */
6390 /* remember used playlists so we can thaw them later */
6391 used_playlists.push_back(pl);
6395 framepos_t start_frame = (*r)->region()->first_frame ();
6396 snap_to (start_frame);
6397 (*r)->region()->set_position (start_frame);
6400 while (used_playlists.size() > 0) {
6401 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6403 used_playlists.pop_front();
6406 commit_reversible_command ();
6410 Editor::close_region_gaps ()
6412 list <boost::shared_ptr<Playlist > > used_playlists;
6414 RegionSelection rs = get_regions_from_selection_and_entered ();
6416 if (!_session || rs.empty()) {
6420 Dialog dialog (_("Close Region Gaps"));
6423 table.set_spacings (12);
6424 table.set_border_width (12);
6425 Label* l = manage (left_aligned_label (_("Crossfade length")));
6426 table.attach (*l, 0, 1, 0, 1);
6428 SpinButton spin_crossfade (1, 0);
6429 spin_crossfade.set_range (0, 15);
6430 spin_crossfade.set_increments (1, 1);
6431 spin_crossfade.set_value (5);
6432 table.attach (spin_crossfade, 1, 2, 0, 1);
6434 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6436 l = manage (left_aligned_label (_("Pull-back length")));
6437 table.attach (*l, 0, 1, 1, 2);
6439 SpinButton spin_pullback (1, 0);
6440 spin_pullback.set_range (0, 100);
6441 spin_pullback.set_increments (1, 1);
6442 spin_pullback.set_value(30);
6443 table.attach (spin_pullback, 1, 2, 1, 2);
6445 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6447 dialog.get_vbox()->pack_start (table);
6448 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6449 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6452 if (dialog.run () == RESPONSE_CANCEL) {
6456 framepos_t crossfade_len = spin_crossfade.get_value();
6457 framepos_t pull_back_frames = spin_pullback.get_value();
6459 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6460 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6462 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6464 begin_reversible_command (_("close region gaps"));
6467 boost::shared_ptr<Region> last_region;
6469 rs.sort_by_position_and_track();
6471 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6473 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6475 if (!pl->frozen()) {
6476 /* we haven't seen this playlist before */
6478 /* remember used playlists so we can thaw them later */
6479 used_playlists.push_back(pl);
6483 framepos_t position = (*r)->region()->position();
6485 if (idx == 0 || position < last_region->position()){
6486 last_region = (*r)->region();
6491 (*r)->region()->trim_front( (position - pull_back_frames));
6492 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6494 last_region = (*r)->region();
6499 while (used_playlists.size() > 0) {
6500 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6502 used_playlists.pop_front();
6505 commit_reversible_command ();
6509 Editor::tab_to_transient (bool forward)
6511 AnalysisFeatureList positions;
6513 RegionSelection rs = get_regions_from_selection_and_entered ();
6519 framepos_t pos = _session->audible_frame ();
6521 if (!selection->tracks.empty()) {
6523 /* don't waste time searching for transients in duplicate playlists.
6526 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6528 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6530 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6533 boost::shared_ptr<Track> tr = rtv->track();
6535 boost::shared_ptr<Playlist> pl = tr->playlist ();
6537 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6540 positions.push_back (result);
6553 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6554 (*r)->region()->get_transients (positions);
6558 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6561 AnalysisFeatureList::iterator x;
6563 for (x = positions.begin(); x != positions.end(); ++x) {
6569 if (x != positions.end ()) {
6570 _session->request_locate (*x);
6574 AnalysisFeatureList::reverse_iterator x;
6576 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6582 if (x != positions.rend ()) {
6583 _session->request_locate (*x);
6589 Editor::playhead_forward_to_grid ()
6595 framepos_t pos = playhead_cursor->current_frame ();
6596 if (pos < max_framepos - 1) {
6598 snap_to_internal (pos, RoundUpAlways, false);
6599 _session->request_locate (pos);
6605 Editor::playhead_backward_to_grid ()
6611 framepos_t pos = playhead_cursor->current_frame ();
6614 snap_to_internal (pos, RoundDownAlways, false);
6615 _session->request_locate (pos);
6620 Editor::set_track_height (Height h)
6622 TrackSelection& ts (selection->tracks);
6624 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6625 (*x)->set_height_enum (h);
6630 Editor::toggle_tracks_active ()
6632 TrackSelection& ts (selection->tracks);
6634 bool target = false;
6640 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6641 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6645 target = !rtv->_route->active();
6648 rtv->_route->set_active (target, this);
6654 Editor::remove_tracks ()
6656 TrackSelection& ts (selection->tracks);
6662 vector<string> choices;
6666 const char* trackstr;
6668 vector<boost::shared_ptr<Route> > routes;
6669 bool special_bus = false;
6671 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6672 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6676 if (rtv->is_track()) {
6681 routes.push_back (rtv->_route);
6683 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6688 if (special_bus && !Config->get_allow_special_bus_removal()) {
6689 MessageDialog msg (_("That would be bad news ...."),
6693 msg.set_secondary_text (string_compose (_(
6694 "Removing the master or monitor bus is such a bad idea\n\
6695 that %1 is not going to allow it.\n\
6697 If you really want to do this sort of thing\n\
6698 edit your ardour.rc file to set the\n\
6699 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6706 if (ntracks + nbusses == 0) {
6710 // XXX should be using gettext plural forms, maybe?
6712 trackstr = _("tracks");
6714 trackstr = _("track");
6718 busstr = _("busses");
6725 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6726 "(You may also lose the playlists associated with the %2)\n\n"
6727 "This action cannot be undone, and the session file will be overwritten!"),
6728 ntracks, trackstr, nbusses, busstr);
6730 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6731 "(You may also lose the playlists associated with the %2)\n\n"
6732 "This action cannot be undone, and the session file will be overwritten!"),
6735 } else if (nbusses) {
6736 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6737 "This action cannot be undone, and the session file will be overwritten"),
6741 choices.push_back (_("No, do nothing."));
6742 if (ntracks + nbusses > 1) {
6743 choices.push_back (_("Yes, remove them."));
6745 choices.push_back (_("Yes, remove it."));
6750 title = string_compose (_("Remove %1"), trackstr);
6752 title = string_compose (_("Remove %1"), busstr);
6755 Choice prompter (title, prompt, choices);
6757 if (prompter.run () != 1) {
6762 Session::StateProtector sp (_session);
6763 DisplaySuspender ds;
6764 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6765 _session->remove_route (*x);
6771 Editor::do_insert_time ()
6773 if (selection->tracks.empty()) {
6777 InsertTimeDialog d (*this);
6778 int response = d.run ();
6780 if (response != RESPONSE_OK) {
6784 if (d.distance() == 0) {
6788 InsertTimeOption opt = d.intersected_region_action ();
6791 get_preferred_edit_position(),
6797 d.move_glued_markers(),
6798 d.move_locked_markers(),
6804 Editor::insert_time (
6805 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6806 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6809 bool commit = false;
6811 if (Config->get_edit_mode() == Lock) {
6815 begin_reversible_command (_("insert time"));
6817 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6819 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6823 /* don't operate on any playlist more than once, which could
6824 * happen if "all playlists" is enabled, but there is more
6825 * than 1 track using playlists "from" a given track.
6828 set<boost::shared_ptr<Playlist> > pl;
6830 if (all_playlists) {
6831 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6833 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6834 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6839 if ((*x)->playlist ()) {
6840 pl.insert ((*x)->playlist ());
6844 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6846 (*i)->clear_changes ();
6847 (*i)->clear_owned_changes ();
6849 if (opt == SplitIntersected) {
6853 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6855 vector<Command*> cmds;
6857 _session->add_commands (cmds);
6859 _session->add_command (new StatefulDiffCommand (*i));
6864 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6866 rtav->route ()->shift (pos, frames);
6874 XMLNode& before (_session->locations()->get_state());
6875 Locations::LocationList copy (_session->locations()->list());
6877 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6879 Locations::LocationList::const_iterator tmp;
6881 bool const was_locked = (*i)->locked ();
6882 if (locked_markers_too) {
6886 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6888 if ((*i)->start() >= pos) {
6889 (*i)->set_start ((*i)->start() + frames);
6890 if (!(*i)->is_mark()) {
6891 (*i)->set_end ((*i)->end() + frames);
6904 XMLNode& after (_session->locations()->get_state());
6905 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6910 _session->tempo_map().insert_time (pos, frames);
6914 commit_reversible_command ();
6919 Editor::fit_selected_tracks ()
6921 if (!selection->tracks.empty()) {
6922 fit_tracks (selection->tracks);
6926 /* no selected tracks - use tracks with selected regions */
6928 if (!selection->regions.empty()) {
6929 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6930 tvl.push_back (&(*r)->get_time_axis_view ());
6936 } else if (internal_editing()) {
6937 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6940 if (entered_track) {
6941 tvl.push_back (entered_track);
6950 Editor::fit_tracks (TrackViewList & tracks)
6952 if (tracks.empty()) {
6956 uint32_t child_heights = 0;
6957 int visible_tracks = 0;
6959 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6961 if (!(*t)->marked_for_display()) {
6965 child_heights += (*t)->effective_height() - (*t)->current_height();
6969 /* compute the per-track height from:
6971 total canvas visible height -
6972 height that will be taken by visible children of selected
6973 tracks - height of the ruler/hscroll area
6975 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6976 double first_y_pos = DBL_MAX;
6978 if (h < TimeAxisView::preset_height (HeightSmall)) {
6979 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6980 /* too small to be displayed */
6984 undo_visual_stack.push_back (current_visual_state (true));
6985 no_save_visual = true;
6987 /* build a list of all tracks, including children */
6990 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6992 TimeAxisView::Children c = (*i)->get_child_list ();
6993 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6994 all.push_back (j->get());
6998 bool prev_was_selected = false;
6999 bool is_selected = tracks.contains (all.front());
7000 bool next_is_selected;
7002 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7004 TrackViewList::iterator next;
7009 if (next != all.end()) {
7010 next_is_selected = tracks.contains (*next);
7012 next_is_selected = false;
7015 if ((*t)->marked_for_display ()) {
7017 (*t)->set_height (h);
7018 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7020 if (prev_was_selected && next_is_selected) {
7021 hide_track_in_display (*t);
7026 prev_was_selected = is_selected;
7027 is_selected = next_is_selected;
7031 set the controls_layout height now, because waiting for its size
7032 request signal handler will cause the vertical adjustment setting to fail
7035 controls_layout.property_height () = _full_canvas_height;
7036 vertical_adjustment.set_value (first_y_pos);
7038 redo_visual_stack.push_back (current_visual_state (true));
7040 visible_tracks_selector.set_text (_("Sel"));
7044 Editor::save_visual_state (uint32_t n)
7046 while (visual_states.size() <= n) {
7047 visual_states.push_back (0);
7050 if (visual_states[n] != 0) {
7051 delete visual_states[n];
7054 visual_states[n] = current_visual_state (true);
7059 Editor::goto_visual_state (uint32_t n)
7061 if (visual_states.size() <= n) {
7065 if (visual_states[n] == 0) {
7069 use_visual_state (*visual_states[n]);
7073 Editor::start_visual_state_op (uint32_t n)
7075 save_visual_state (n);
7077 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7079 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7080 pup->set_text (buf);
7085 Editor::cancel_visual_state_op (uint32_t n)
7087 goto_visual_state (n);
7091 Editor::toggle_region_mute ()
7093 if (_ignore_region_action) {
7097 RegionSelection rs = get_regions_from_selection_and_entered ();
7103 if (rs.size() > 1) {
7104 begin_reversible_command (_("mute regions"));
7106 begin_reversible_command (_("mute region"));
7109 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7111 (*i)->region()->playlist()->clear_changes ();
7112 (*i)->region()->set_muted (!(*i)->region()->muted ());
7113 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7117 commit_reversible_command ();
7121 Editor::combine_regions ()
7123 /* foreach track with selected regions, take all selected regions
7124 and join them into a new region containing the subregions (as a
7128 typedef set<RouteTimeAxisView*> RTVS;
7131 if (selection->regions.empty()) {
7135 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7136 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7139 tracks.insert (rtv);
7143 begin_reversible_command (_("combine regions"));
7145 vector<RegionView*> new_selection;
7147 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7150 if ((rv = (*i)->combine_regions ()) != 0) {
7151 new_selection.push_back (rv);
7155 selection->clear_regions ();
7156 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7157 selection->add (*i);
7160 commit_reversible_command ();
7164 Editor::uncombine_regions ()
7166 typedef set<RouteTimeAxisView*> RTVS;
7169 if (selection->regions.empty()) {
7173 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7174 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7177 tracks.insert (rtv);
7181 begin_reversible_command (_("uncombine regions"));
7183 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7184 (*i)->uncombine_regions ();
7187 commit_reversible_command ();
7191 Editor::toggle_midi_input_active (bool flip_others)
7194 boost::shared_ptr<RouteList> rl (new RouteList);
7196 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7197 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7203 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7206 rl->push_back (rtav->route());
7207 onoff = !mt->input_active();
7211 _session->set_exclusive_input_active (rl, onoff, flip_others);
7218 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7220 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7221 lock_dialog->get_vbox()->pack_start (*padlock);
7223 ArdourButton* b = manage (new ArdourButton);
7224 b->set_name ("lock button");
7225 b->set_text (_("Click to unlock"));
7226 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7227 lock_dialog->get_vbox()->pack_start (*b);
7229 lock_dialog->get_vbox()->show_all ();
7230 lock_dialog->set_size_request (200, 200);
7234 /* The global menu bar continues to be accessible to applications
7235 with modal dialogs, which means that we need to desensitize
7236 all items in the menu bar. Since those items are really just
7237 proxies for actions, that means disabling all actions.
7239 ActionManager::disable_all_actions ();
7241 lock_dialog->present ();
7247 lock_dialog->hide ();
7250 ActionManager::pop_action_state ();
7253 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7254 start_lock_event_timing ();
7259 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7261 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7265 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7267 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7268 Gtkmm2ext::UI::instance()->flush_pending ();
7272 Editor::bring_all_sources_into_session ()
7279 ArdourDialog w (_("Moving embedded files into session folder"));
7280 w.get_vbox()->pack_start (msg);
7283 /* flush all pending GUI events because we're about to start copying
7287 Gtkmm2ext::UI::instance()->flush_pending ();
7291 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));